home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Tele / C / Comet2.1.3 Folder / Comet / event.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-22  |  67.3 KB  |  2,825 lines  |  [TEXT/????]

  1. /*
  2.     Copyright Cornell University 1986.  All rights are reserved.
  3.     
  4.     event.c contains routines servicing the Mac event loop, along
  5.         with other routines supporting MultiFinder etc.
  6.     The text selection copy/print selection routines are also included here.
  7.     
  8. */
  9.  
  10. #include     <em.h>
  11.  
  12. #include    <3270.h>
  13. #include    <rcodes.h>
  14. #include    <h19.h>
  15. #include    <errors.h>
  16. #include     <util.h>
  17. #include     <macdefs.h>
  18. #include     <resdefs.h>
  19. #include     <cntldefs.h>
  20. #include     <config.h>
  21. #include    "menudefs.h"
  22.  
  23. #include     <ctype.h>
  24.  
  25. #define KEYPDIAL            /* use a dialog for keypad selection  */        
  26.  
  27. short mousecurson;            /* is the mouse cursor drawn? */
  28. short modaldialog;            /* is a modaldialog active outside the Mac task?  skip event loop! */
  29. long creator = '3278';        /* creator for file info */
  30.  
  31. short autokey;                /* key is in auto mode */
  32. short autokeycommand;        /* autoKey menu commands use this flag to suppress menu flashing */
  33. short autokeypersist;        /* indicates autokey has been on */
  34. timer *autokeywait;
  35. extern int clrautokeywait();
  36.  
  37. char fileopenerr[] = "Error opening file";
  38. char filecreateerr[] = "Error creating file";
  39. char filewriteerr[] = "Error writing to file";
  40. char untitled[] = "\PUntitled";
  41. char copyerr[] = "to perform copy";
  42.  
  43. unsigned long mousedelay;        /* keeps last tick for double-click */
  44. short doubleclick;                /* a double click occurred */
  45. short mfpresent = TRUE;            /* we're under MultiFinder */                        
  46. short mfbackground;                /* we're in the background under MultiFinder */                        
  47.  
  48. Handle scraptemp;                /* used for Scrap Appends */
  49.  
  50. extern DialogPtr nnrdptr;    /* network not responding */
  51.  
  52. /* stuff now in menu.c */
  53. extern MenuHandle menu[];
  54. extern char scrapzeroed;                /* has scrap been zeroed yet? */
  55.  
  56. extern short darefnum;
  57. extern PicHandle iconpict;
  58.  
  59. pascal void        RepAction();
  60.  
  61. clrautokeywait()
  62. {
  63.     autokeypersist = FALSE;
  64. }
  65.  
  66. /* the BIG EVENT LOOP! */
  67.  
  68. user_act()
  69. {
  70.     while (TRUE) {
  71.         SystemTask();                /* keep this if/until we use WaitNextEvent */
  72.  
  73.         if (cutcpopen)
  74.             datayield();
  75.  
  76.         if (modaldialog)
  77.             return(-1);
  78.             
  79.         /* get all Macintosh events waiting in the queue */
  80.         /* before doing tn key handling */
  81.         if ( ! GetNextEvent(everyEvent, &myEvent)) {
  82.             /* ignore system events */
  83.             if (myEvent.what == nullEvent)  {
  84.                 /* out of events, go around loop and yield */
  85.                 return(0);
  86.             }
  87.             else
  88.                 /* get the next event */
  89.                 continue;
  90.         }
  91.         if (IsDialogEvent(&myEvent)) {
  92.             /* the net not responding dialog is up--net/nnr.c */
  93.             short itemhit;
  94.  
  95.             if (myEvent.what == mouseDown) {
  96.                 /* bring up keywindow, ignore the mouseDown */
  97.                 selectwindow(keywindow);
  98.                 continue;
  99.             }
  100.             else if (DialogSelect(&myEvent, &nnrdptr, &itemhit))
  101.                 /* ignore dialog events handled by Dialog Mgr */
  102.                 continue;
  103.         }
  104.         switch (myEvent.what) {
  105.             case nullEvent: {
  106.                 /* out of events, return */
  107.                 return(0);
  108.             }
  109.             case diskEvt: {
  110.                 diskevent(&myEvent);
  111.                 break;
  112.             }
  113.             case networkEvt: {
  114.                 /* appletalk network event has occured */
  115.                 break;
  116.             }
  117.             case app4Evt:  {
  118.                 /* suspend/resume events */
  119.                 mfswitch(&myEvent);
  120.                 break;
  121.             }
  122.             case autoKey: 
  123.                 autokey = TRUE;
  124.                 if (myEvent.modifiers & cmdKey)
  125.                     autokeycommand = TRUE;
  126.                     
  127.                 if (autokeywait == NULL) {
  128.                     /* allocate a timer to maintain autokeypersist */
  129.                     autokeywait = tm_alloc();
  130.                 }
  131.                 if (autokeywait != NULL) {
  132.                     autokeypersist = TRUE;
  133.                     tm_tset(60, clrautokeywait, NULL, autokeywait);
  134.                 }
  135.                 
  136.             case keyDown: {
  137.                 unsigned char thechar;
  138.                 unsigned char keycode;
  139.                 long comm;
  140.                 
  141.                 thechar = myEvent.message & 0xff;
  142.                 keycode = (myEvent.message >> 8) & 0xff;
  143.                 if (keydp) {
  144. #ifdef USETEXTWINDOWS                    
  145.                     if (FrontWindow() == keydp->textwindow) {
  146.                         /* text window is up, put keystrokes in it... */
  147.                         
  148.                         if (keydp->texthand == NULL)
  149.                             break;
  150.                         if (myEvent.modifiers & cmdKey 
  151.                                 && keycode < 52 
  152.                                 && !(myEvent.modifiers & optionKey) 
  153.                                 && !(myEvent.modifiers & ctrlKey)
  154.                             ) {
  155.                             /* of the modifier keys, only the command key/caps lock are down */
  156.                             /* and the keycode is less than the keypad codes */
  157.                             /* is this a menu key ? */
  158.                             if (thechar == '.') {
  159.                                 /* user wants to abort actions */
  160.                                 flushactions(keydp);
  161.                                 break;
  162.                             }
  163.                             else if (comm = MenuKey(thechar)) {
  164.                                 docommand(comm);
  165.                             }
  166.                             break;
  167.                         }
  168.                         TEKey(thechar, keydp->texthand);
  169.                     
  170.                         /* Hornig: make sure selection in in view */
  171.                         textctlupd(keydp);
  172.                         SelView(keydp);
  173.                     }
  174.                     else 
  175. #endif
  176.                     {
  177.                         if (keydp->termset && !keydp->icon_up) {
  178.                             /* do emulator keymapping */
  179.                             keymap(keycode, thechar, myEvent.modifiers);
  180.                         }
  181.                         else {
  182.                             /*     We have no concept of who we are yet! 
  183.                                 Do not interfere with Telnet negotiations!
  184.                                 do menus though...*/
  185.         
  186.                             if (myEvent.modifiers & cmdKey 
  187.                                     && keycode < 52 
  188.                                     && !(myEvent.modifiers & optionKey) 
  189.                                     && !(myEvent.modifiers & shiftKey)
  190.                                     && !(myEvent.modifiers & ctrlKey)
  191.                                 ) {
  192.                                 /* of the modifier keys, only the command key/caps lock are down */
  193.                                 /* and the keycode is less than the keypad codes */
  194.                                 /* is this a menu key ? */
  195.                                 if (thechar == '.') {
  196.                                     /* user wants to abort actions */
  197.                                     flushactions(keydp);
  198.                                     break;
  199.                                 }
  200.                                 else if (comm = MenuKey(thechar)) {
  201.                                     docommand(comm);
  202.                                 }
  203.                             }
  204.                             else if (keydp->icon_up) {
  205.                                 /* ignore keystrokes when the window is shrunk */
  206.                                 beep();
  207.                                 break;
  208.                             }
  209.                             break;
  210.                         }
  211.                     }
  212.                 }
  213.                 else {
  214.                     /* do menu commands only */
  215.                     if (comm = MenuKey(thechar)) {
  216.                         docommand(comm);
  217.                     }
  218.                 }
  219.                 if (autokey)
  220.                     /* break out of event loop so other stuff gets serviced */
  221.                     return(0);
  222.                 break;
  223.             }
  224.             case keyUp: {
  225.                 if (autokeycommand) {
  226.                     autokeycommand = FALSE;
  227.                     HiliteMenu(0);
  228.                 }
  229.                 autokey = FALSE;
  230.                 break;
  231.             }
  232.             case mouseUp: {
  233.                 mousedelay = cticks;
  234.                 break;
  235.             }
  236.             case mouseDown: {
  237.                 short windowpart;
  238.                 WindowPtr clickwind;
  239.                 struct winds * twp;
  240.                 
  241.                 windowpart = FindWindow(pass(myEvent.where), &clickwind);
  242.                 
  243.                 if (clickwind != NULL)
  244.                     twp = ((WindowPeek) clickwind)->refCon;
  245.                     /* this must be one of the keydp context window members */
  246.                 switch (windowpart) {
  247.                     case inGoAway: {
  248.                         /* do the right thing to close a window */
  249. #ifdef USETEXTWINDOWS
  250.                         if (clickwind == twp->textwindow) {
  251.                             HideWindow(twp->textwindow);
  252.                             selectwindow(twp->emwindow);
  253.                             twp->hidetextwindow = TRUE;
  254.                         }
  255.                         else
  256. #endif
  257.                             menufile(WMCLOSEWIND);    /* handle through menu routine */
  258.                         break;
  259.                     }
  260.                     case inMenuBar: {
  261.                         docommand(MenuSelect(pass(myEvent.where)));
  262.                         break;
  263.                     }
  264.                     case inSysWindow: {
  265.                         SystemClick(&myEvent, clickwind);
  266.                         break;
  267.                     }
  268.                     case inDrag: {
  269.                         Point thept;
  270.                         Point oldpoint;
  271.                         
  272.                         SetPort(clickwind);
  273.                         thept.v = clickwind->portRect.top;
  274.                         thept.h = clickwind->portRect.left;
  275.                         LocalToGlobal(&thept);
  276.                         oldpoint = thept;
  277.     
  278.                         if (clickwind != FrontWindow()) {
  279.                             selectwindow(clickwind);
  280.                         }
  281.                         DragWindow(clickwind, pass(myEvent.where), &dragrect);
  282.  
  283.                         if (((WindowPeek) clickwind)->windowKind == EMWINDKIND) {
  284.                             thept.v = clickwind->portRect.top;
  285.                             thept.h = clickwind->portRect.left;
  286.                             LocalToGlobal(&thept);
  287.                             alignwind(twp, (thept.h < oldpoint.h) ? TRUE : FALSE);
  288.                                 /* shift left if that was the direction of drag */
  289.     
  290.                             testds(twp); 
  291.  
  292. #ifdef MOVETEXTWIND                            
  293.                             thept.v = clickwind->portRect.top;
  294.                             thept.h = clickwind->portRect.left;
  295.                             LocalToGlobal(&thept);
  296.  
  297.                             /* now drag the textwindow along with it */
  298.                             textwmove(twp, (thept.h - oldpoint.h), (thept.v - oldpoint.v));
  299. #endif
  300.                         }    
  301.                         break;
  302.                     }
  303.                     case inZoomIn:
  304.                     case inZoomOut: {
  305.                         if (clickwind != FrontWindow()) {
  306.                             selectwindow(clickwind);
  307.                             break;
  308.                         }
  309.                         if (TrackBox(clickwind, pass(myEvent.where), windowpart)) {
  310.                             shrinkwindow(keydp);
  311.                             /* change the window font size
  312.                             menuctrl(MSCREENSIZE);
  313.                              */
  314.                         }
  315.                         break;
  316.                     }
  317.                     case inGrow:
  318.                     case inContent: {
  319.                         unsigned clicktime = cticks - mousedelay;
  320.                         
  321.                         if (((WindowPeek) clickwind)->windowKind == ICONWINDKIND) {
  322.                             if (clickwind != FrontWindow()) {
  323.                                 selectwindow(clickwind);
  324.                                 DragWindow(clickwind, pass(myEvent.where), &dragrect);
  325.                             }
  326.                             else if (clicktime <= GetDblTime()) {
  327.     /* a candidate double click, we would do it on mouseUp to be like Finder 
  328.         BUT the mouseUp event NEVER ARRIVES!!!??? */
  329.                                 
  330. #ifdef USETEXTWINDOWS
  331.                                 expandwindow(twp);
  332. #else
  333.                                 selectwindow(twp->emwindow);
  334.                                 ShowWindow(twp->emwindow);
  335.                                 HideWindow(iconwindow);
  336.                                 
  337.                                 keydp->icon_up = FALSE;    /* restore keyboard */
  338.                                 keydp->iconhigh = FALSE;
  339. #endif
  340.  
  341.                                 shownnr();                            /* if "net not receiving" is up, show it */
  342.                             }
  343.                             else
  344.                                 DragWindow(clickwind, pass(myEvent.where), &dragrect);
  345.                             mousedelay = cticks;
  346.                         }
  347.                         else if (((WindowPeek) clickwind)->windowKind == EMWINDKIND) {
  348.                             /* we're in keywindow, routines assume this */
  349.                             if (clickwind != FrontWindow()) {
  350.                                 selectwindow(clickwind);
  351.                             }
  352.                             else {
  353.                                 SetPort(twp->emwindow);
  354.                                 if (clicktime <= GetDblTime())
  355.                                     doubleclick = TRUE;
  356.                                 else 
  357.                                     doubleclick = FALSE;
  358.                                 mousedelay = cticks + clickdelay;
  359.                                     /* more time is needed due to delay in emmouseclick() */
  360.                                 
  361.                                 GlobalToLocal(&myEvent.where);
  362.                                 emmouseclick(&myEvent.where);
  363.                             }
  364.                         }
  365. #ifdef USETEXTWINDOWS                    
  366.                         else if (((WindowPeek) clickwind)->windowKind == TEXTWINDKIND) {
  367.                             ControlHandle    theCtlHand;
  368.                             
  369.                             if (clickwind != FrontWindow()) {
  370.                                 selectwindow(clickwind);
  371.                                 break;
  372.                             }
  373.                             SetPort(twp->textwindow);
  374.                             if (keydp->texthand == NULL)
  375.                                 break;
  376. #ifdef SIZETEXTWINDOW
  377.                             if (windowpart == inGrow) {
  378.                                 /* resize the window */
  379.                                 Rect growrect;
  380.                                 unsigned long growth;
  381.                                 
  382.                                 getcontext(twp);
  383.                                 
  384.                                 /* set min/max grow limits */
  385.                                 growrect.top = 50;
  386.                                 growrect.left = 50;
  387.                                 growrect.bottom = 32000;
  388.                                 growrect.right = 32000;
  389.  
  390.                                 growth = GrowWindow(twp->textwindow, 
  391.                                     pass(myEvent.where), 
  392.                                     &growrect);
  393.                                 textwsize((short) (growth & 0x0000FFFF),
  394.                                     (short) ((growth >> 16) & 0x0000FFFF));
  395.                                 break;
  396.                             }
  397. #endif
  398.                             GlobalToLocal(&myEvent.where);
  399.                             if (PtInRect(pass(myEvent.where), &(*twp->texthand)->viewRect)) {
  400.                                 /* in text */
  401.                                 TEClick(pass(myEvent.where), (myEvent.modifiers & shiftKey) ? TRUE : FALSE, twp->texthand);
  402.                             }
  403.                             /* else check scrollbar, Hornig code */
  404.                             else if( FindControl( pass(myEvent.where), clickwind, &theCtlHand ) )
  405.                             {
  406.                                 if( TestControl( theCtlHand, pass(myEvent.where) ) == inThumb )
  407.                                 {                            /* scroll bar inThumb requires special TrackControl */
  408.                                     if( TrackControl( theCtlHand, pass(myEvent.where), NULL ) )
  409.                                         MoveElevator( theCtlHand );
  410.                                 }
  411.                                 else TrackControl( theCtlHand, pass(myEvent.where), (ProcPtr) RepAction );
  412.                             }
  413.                         }
  414. #endif
  415. #ifdef USEHELPWINDOW                    
  416.                         else if (((WindowPeek) clickwind)->windowKind == HELPWINDKIND) {
  417.                             if (clickwind != FrontWindow()) {
  418.                                 selectwindow(clickwind);
  419.                                 break;
  420.                             }
  421.                             helpwhandle();
  422.                         }
  423. #endif
  424.                         else if (clickwind != FrontWindow()) {
  425.                             selectwindow(clickwind);
  426.                         }
  427.                         break;
  428.                     }
  429.                 }
  430.                 break;
  431.             }
  432.             case activateEvt: {
  433.                 activatewind();
  434.                 break;
  435.             }
  436.             case updateEvt: {
  437.                 updatewind();
  438.                 break;
  439.             }
  440.         }
  441.         /* break;        just do loop once */
  442.     }
  443. }
  444.  
  445.  
  446. activatewind()
  447. {
  448.     GrafPtr oldport;
  449.     WindowPtr actwind;
  450.     int menuredraw = FALSE;
  451.     struct winds * twp;
  452.     
  453.     actwind = myEvent.message;
  454.     twp = ((WindowPeek) actwind)->refCon;
  455.     if (((WindowPeek) actwind)->windowKind == EMWINDKIND) {
  456.         if (myEvent.modifiers & activeFlag) {
  457.             keywindow = actwind;
  458.             keydp = ((WindowPeek) keywindow)->refCon;
  459.             iconwindow = keydp->iconwindow;
  460.             twp->edit = FALSE;
  461.  
  462.             SetPort(keywindow);
  463.             
  464.             /* do menu stuff */
  465.             menuredraw = menucheck(keydp);
  466.             
  467.             /* TODO what about bkrd_act when textwindow or iconwindow
  468.                 comes up?  should be reset? */
  469.             bkrd_act = 0;
  470.             testds(keydp);
  471.                 
  472.         }
  473.         else {
  474.             emwdeactivate();
  475.         }
  476.     }
  477. #ifdef USETEXTWINDOWS
  478.     else if (((WindowPeek) actwind)->windowKind == TEXTWINDKIND) {
  479.         /* make the associated emulator window the key window */
  480.         if (myEvent.modifiers & activeFlag) {
  481.             keywindow = actwind;
  482.             keydp = ((WindowPeek) keywindow)->refCon;
  483.             iconwindow = keydp->iconwindow;
  484.             twp->edit = TRUE;
  485.  
  486.             SetPort(keywindow);
  487.  
  488.             if (twp->texthand) {
  489.                 TEActivate(twp->texthand);
  490.                 scraptote();
  491.                 twp->textscrapped = FALSE;
  492.  
  493.                 ShowControl(twp->vBarHand);
  494.             }
  495.             menuredraw = menucheck(keydp);
  496.         }
  497.         else {
  498.             if (twp->texthand) {
  499.                 TEDeactivate(twp->texthand);
  500.                 HideControl(twp->vBarHand);
  501.                 if (twp->textscrapped) {
  502.                     tetoscrap(*TEScrHandle, TEScrLen);
  503.                     twp->textscrapped = FALSE;
  504.                 }
  505.             }
  506.         }
  507.         drawgrowicon(actwind);
  508.     }
  509. #endif
  510. #ifdef USEHELPWINDOW
  511.     else if (((WindowPeek) actwind)->windowKind == HELPWINDKIND) {
  512.         helpwhandle();
  513.     }
  514. #endif
  515.     else if (((WindowPeek) actwind)->windowKind == ICONWINDKIND) {
  516.         /* force invert redraw on MF switch */
  517.         
  518.         if (myEvent.modifiers & activeFlag) {
  519.             if (keydp != ((WindowPeek) actwind)->refCon) {
  520.                 keydp = ((WindowPeek) actwind)->refCon;
  521.                 keywindow = keydp->emwindow;    
  522.                 /* make emwindow key by default when new icon selected*/
  523.             }
  524.             iconwindow = actwind;
  525.         }
  526.  
  527.         GetPort(&oldport);
  528.         SetPort(twp->iconwindow);
  529.         InvalRect(&((GrafPtr) twp->iconwindow)->portRect);
  530.         SetPort(oldport);
  531.     }
  532.     
  533.  
  534.     if (myEvent.modifiers & activeFlag) {
  535.         if (!mfpresent && darefnum) {
  536.             /* manage menus for DA's */
  537.             emedit(keydp, TRUE);
  538.             DrawMenuBar();
  539.             setscript(1L);        /* pass E,I,N, U keys */
  540.         }
  541.         else if (menuredraw)
  542.             DrawMenuBar();
  543.     }
  544.     else {
  545.         if (!mfpresent && darefnum) {
  546.             emedit(keydp, FALSE);
  547.             DrawMenuBar(); 
  548.         }
  549.     }
  550. }
  551.  
  552.  
  553. updatewind()
  554. {
  555.     GrafPtr oldport;
  556.     WindowPtr updwind;
  557.     struct winds * twp;
  558.     
  559.     updwind = myEvent.message;
  560.     twp = ((WindowPeek) updwind)->refCon;
  561.     
  562.     GetPort(&oldport);
  563.     if (((WindowPeek) updwind)->windowKind == EMWINDKIND) {
  564.         getcontext(twp);
  565.         (*twp->updatewind)();
  566.     }
  567. #ifdef USETEXTWINDOWS                    
  568.     else if (((WindowPeek) updwind)->windowKind == TEXTWINDKIND) {
  569.         SetPort(twp->textwindow);
  570.         BeginUpdate(updwind);
  571.         EraseRect(&(*updwind->visRgn)->rgnBBox);
  572.  
  573.         if (twp->texthand) {
  574.             TEUpdate(&(*updwind->visRgn)->rgnBBox, twp->texthand);
  575.             UpdtControl(updwind, updwind->visRgn );
  576.         }
  577.         drawgrowicon(updwind);
  578.         
  579.         EndUpdate(updwind);
  580.     }
  581. #endif
  582. #ifdef USEHELPWINDOW                    
  583.     else if (((WindowPeek) updwind)->windowKind == HELPWINDKIND) {
  584.         helpwhandle();
  585.     }
  586. #endif
  587.     else if (((WindowPeek) updwind)->windowKind == ICONWINDKIND) {
  588.         /* redraw icon window--add title to picture */
  589.         int titlewidth;
  590.         short hpos;
  591.         Rect destrect;
  592.         struct winds * cons;
  593.         
  594.         SetPort(updwind);
  595.         BeginUpdate(updwind);
  596.  
  597.         cons = ((WindowPeek) updwind)->refCon;
  598.  
  599.         destrect.top = 0;
  600.         destrect.left = 0;
  601.         destrect.bottom = 33;
  602.         destrect.right = 46;
  603.             /* dimensions of the telnet picture */
  604.         DrawPicture(iconpict, &destrect);
  605.         if (cons->iconhigh)
  606.             /* show that data has arrived */
  607.             InvertRect(&destrect);
  608.         
  609.         destrect.top = 33;
  610.         destrect.bottom = 45;
  611.         EraseRect(&destrect);
  612.         
  613.         if (cons->hhostname != NULL) {
  614.             HLock(cons->hhostname);
  615.         
  616.             titlewidth = StringWidth(*cons->hhostname);
  617.             titlewidth /= 2;
  618.             hpos = 22 - titlewidth;
  619.             if (hpos < 4)
  620.                 hpos = 4;
  621.             MoveTo(hpos, 42);
  622.             
  623.             /* draw the host title */
  624.             DrawString(*cons->hhostname);
  625.             HUnlock(cons->hhostname);
  626.         }
  627.         
  628.         if (cons->iconwindow == FrontWindow() && !mfbackground) {
  629.             /* invert the title on the icon to show we're up top */
  630.             InvertRect(&destrect);
  631.         }
  632.  
  633.         EndUpdate(updwind);
  634.     }
  635.     else {
  636.         /* we don't care, throw out the update event */
  637.         SetPort(updwind);
  638.         BeginUpdate(updwind);
  639.         EndUpdate(updwind);
  640.     }
  641.     SetPort(oldport);
  642. }
  643.  
  644. /* mousedown or keydown events on the event queue indicate user might 
  645.     want a break ... */
  646.     
  647. user_intr()
  648. {
  649.     EventRecord junkevt;
  650.  
  651.     if (EventAvail(keyDownMask | mDownMask, &junkevt))
  652.         return(TRUE);
  653.     else
  654.         return(FALSE);
  655. }
  656.  
  657.  
  658. /* the tick counter has wrapped; reset all counters so timers will pop */
  659.  
  660. user_tmwrap()
  661. {
  662.     tickcursor = 0;
  663.     tickstats = 0;
  664.     tickserial = 0;
  665.     mousedelay = 0;
  666.     cursalarm = 0;
  667. }
  668.  
  669. /* make the top window shrink down into an icon */
  670.  
  671. shrinkwindow(twp)
  672. struct winds * twp;
  673. {
  674.     GrafPtr oldport;
  675.     
  676.     twp->curson = FALSE;
  677.     twp->icon_up = TRUE;                /* lock the keyboard */
  678.  
  679.     ShowWindow(twp->iconwindow);
  680.     HideWindow(twp->emwindow);
  681. #ifdef USETEXTWINDOWS
  682.     HideWindow(twp->textwindow);
  683. #endif
  684.  
  685.     GetPort(&oldport);
  686.     SetPort(twp->iconwindow);
  687.     InvalRect(&((GrafPtr) twp->iconwindow)->portRect);
  688.     SetPort(oldport);
  689.  
  690.     /* hidennr();                            hide net not responding dialog */
  691. }
  692.  
  693.  
  694. /* make the top window expand from an icon to an emulator screen */
  695.  
  696. expandwindow(twp)
  697. struct winds * twp;
  698. {
  699.     GrafPtr oldport;
  700.     
  701.     GetPort(&oldport);
  702.     SetPort(twp->iconwindow);
  703.  
  704. #ifdef USETEXTWINDOWS
  705.     if (twp->edit) {
  706.         if (twp->textwindow != FrontWindow()) {
  707.             /* don't select it unless necessary... */
  708.             selectwindow(twp->emwindow);
  709.             ShowWindow(twp->emwindow);
  710.     
  711.             selectwindow(twp->textwindow);
  712.             ShowWindow(twp->textwindow);
  713.         }
  714.     }
  715.     else {
  716.         if (twp->emwindow != FrontWindow()) {
  717.             if (!twp->hidetextwindow) {
  718.                 selectwindow(twp->textwindow);
  719.                 ShowWindow(twp->textwindow);
  720.             }
  721.             selectwindow(twp->emwindow);
  722.             ShowWindow(twp->emwindow);
  723.         }
  724.     }
  725. #else
  726.     if (twp->emwindow != FrontWindow()) {
  727.         selectwindow(twp->emwindow);
  728.         ShowWindow(twp->emwindow);
  729.     }
  730. #endif
  731.     HideWindow(twp->iconwindow);
  732.  
  733.     twp->icon_up = FALSE;            /* restore keyboard */
  734.     twp->iconhigh = FALSE;
  735.  
  736.     SetPort(oldport);
  737. }
  738.  
  739.  
  740. /* are we running under the multifinder?  Set mode accordingly if not.
  741.     This handles problem due to MF launches into background so drawing 
  742.     must be disabled--but with no MF present, bkrd = TRUE assumption locks out
  743.     drawing forever under plain Finder which never offers "bring to MF 
  744.     foreground" event.  We detect presence of MF by examining the Apple
  745.     menu; if "Finder" is present in the Apple menu, we're under MF ... */
  746.  
  747. chkmultifinder()
  748. {
  749.     char * datap;
  750.     int stop = 100;
  751.     
  752.     if (environs.systemVersion >= 0x0700)
  753.         /* MultiFinder is all there is under System > 7.0 */
  754.         return(TRUE);
  755.         
  756.     datap = (char *) (&(*menu[APPLEMENU])->menuData);
  757.     datap += *datap + 1;
  758.         /* skip the menu name */
  759.     
  760.     while (--stop) {
  761.         /* more than 100 menu items in the apple menu indicates a problem--
  762.             "you're not supposed to examine this record!" IM-V, I-364 */
  763.         if (*datap == 0)
  764.             /* we've run out of items to test, MF not present */
  765.             break;
  766.         if (EqualString(datap, "\PFinder", (Boolean) TRUE, (Boolean) TRUE))
  767.             /* found item name "Finder"--we are under MultiFinder! */
  768.             return(TRUE);
  769.         datap += *datap + 5;        
  770.             /* skip this name & rest of item data and continue */
  771.     }
  772.     mfpresent = FALSE;
  773.     mfbackground = FALSE;
  774.     return(FALSE);
  775. }
  776.  
  777.  
  778. /* disallow drawing because we're waiting on an update event
  779.     which implies there's a big white patch where the cursor
  780.     might have been ON...
  781.     
  782.     or the emulator is disabled.
  783. */
  784.  
  785. extern short appclosing;
  786.  
  787. updatewait()
  788. {
  789.     EventRecord junkevt;
  790.     
  791.     if (appclosing) {
  792.         /* when the application is closing we might have a hang if
  793.             we wait for an update... */
  794.         return(FALSE);
  795.     }
  796.     
  797.     if (emdp->emdisable || emdp->mfwait)
  798.         return(TRUE);
  799.         
  800.     if (EventAvail(updateMask, &junkevt))
  801.         /* no updates waiting, forget it */
  802.         return(TRUE);
  803.             
  804.     return(FALSE);
  805. }
  806.  
  807.  
  808. /* disallow cursor drawing because we're waiting on an update event
  809.     which implies there's a big white patch where the cursor
  810.     might have been ON...
  811.     
  812.     or the emulator is disabled.
  813. */
  814.  
  815. cupdatewait(twp)
  816. struct winds * twp;
  817. {
  818.     EventRecord junkevt;
  819.  
  820.     if (appclosing) {
  821.         /* when the application is closing we might have a hang if
  822.             we wait for an update... */
  823.         return(FALSE);
  824.     }
  825.     
  826.     if (twp->emdisable || twp->mfwait)
  827.         return(TRUE);
  828.         
  829.     if (EventAvail(updateMask, &junkevt))
  830.         /* updates are waiting, forget it */
  831.         return(TRUE);
  832.         
  833.     return(FALSE);
  834. }
  835.  
  836.  
  837. /* handle suspend/resume events */
  838.  
  839. mfswitch(anevent)
  840. EventRecord * anevent;
  841. {
  842.     Point thept;
  843.     GrafPtr oldport;
  844.     struct winds ** conp = conns;
  845.     struct winds * conend = &conp[conncount];
  846.     register struct winds * twp;
  847.     struct winds * clicktwp;
  848.     GrafPtr frontwind;
  849.     GrafPtr movewind;
  850.  
  851.  
  852.     if (! (anevent->message & 0x01000000L)) {
  853.         return(FALSE);
  854.     }
  855.     /* go through window list & shunt aside all
  856.         w/ mfbackground set ... */
  857.     
  858.     frontwind = FrontWindow();
  859.     if (anevent->message & 1) {
  860.         /*    MultiFinder is putting us back on top, we handle Suspend/Resume
  861.             we are "MultiFinder friendly" so we activate our window
  862.             if we had a private scrap we'd coerce it 
  863.             */
  864.         movewind = NULL;
  865.         clicktwp = NULL;
  866.         mfbackground = FALSE;
  867.         setscript(1L);
  868.  
  869.         GetPort(&oldport);
  870.         
  871.         /* go through window list to expand autoshrink iconwindows */
  872.         while (conp < conend) {
  873.             twp = *conp++;
  874.             if (twp == NULL || twp->emwindow == NULL)
  875.                 continue;
  876.                 
  877.             if (twp->icon_up) {
  878.                 /* the icon window is up rather than the emulator window;
  879.                     move it around or bring it up; only bring up 
  880.                     windows if not a move to facilitate placing icons */
  881.                 
  882.                 SetPort(twp->iconwindow);
  883.                 GetMouse(&thept);
  884.                 if (PtInRect(pass(thept), &((GrafPtr) twp->iconwindow)->portRect) ) {
  885.                     /* mouse down on iconwindow, drag */
  886.                     selectwindow(twp->iconwindow);    /* added so windows other than top wind*/
  887.                     if (Button()) {
  888.                         LocalToGlobal(&thept);
  889.                         DragWindow(twp->iconwindow, pass(thept), &dragrect);
  890.                         mousedelay = cticks;
  891.                         movewind = twp->iconwindow;
  892.                     }
  893.                     clicktwp = twp;
  894.                 }
  895.             }
  896.         }
  897.         /* go through the window list, expand autoshrink iconwindows and set drawing mode */
  898.         conp = conns;
  899.         while (conp < conend) {
  900.             twp = *conp++;
  901.             if (twp == NULL || twp->emwindow == NULL)
  902.                 continue;
  903.                 
  904.             testds(twp);
  905.             
  906.             if (twp->icon_up) {
  907.                 if (movewind == NULL && twp->autoshrink) {
  908.                     /* if autoshrink on, expand UNLESS the user was moving
  909.                         an icon about */
  910.                         
  911.                     expandwindow(twp);
  912.                     /* make sure cursor won't be inverted until update event arrives 
  913.                         on the queue;  likewise make sure we have one (InvalRect will force redraw) */
  914.                     twp->mfwait = TRUE;
  915.                     InvalRect(&twp->dubshiftrect);
  916.                 }
  917.                 else
  918.                     InvalRect(&((GrafPtr) twp->iconwindow)->portRect);
  919.             }
  920.             else {
  921.                 /* make sure cursor won't be inverted until update event arrives 
  922.                     on the queue;  likewise make sure we have one (InvalRect will force redraw) */
  923.                 SetPort(twp->emwindow);
  924.                 twp->mfwait = TRUE;
  925.                 InvalRect(&twp->dubshiftrect);
  926.             }
  927.         }
  928.         if (oldport)
  929.             SetPort(oldport);
  930.  
  931.         if (clicktwp) {
  932.             if (movewind == NULL) {
  933.                 /* if not a drag, make sure the one that was touched comes up on top */
  934.                 if (clicktwp->autoshrink) {
  935.                     expandwindow(clicktwp);
  936.                 }
  937.                 else {
  938.                     selectwindow(clicktwp->iconwindow);
  939.                 }
  940.             }
  941.         }
  942.         else if (keywindow != NULL) {
  943.             /*  && keywindow == FrontWindow() */
  944.             SetPort(keywindow);
  945.             twp = ((WindowPeek) keywindow)->refCon;
  946.             
  947.             if (((WindowPeek) keywindow)->windowKind == EMWINDKIND) {
  948.                 bkrd_act = 0;
  949.             }
  950. #ifdef USETEXTWINDOWS                    
  951.             else if (((WindowPeek) keywindow)->windowKind == TEXTWINDKIND) {
  952.                 /* update the TE Scrap */
  953.                 twp = ((WindowPeek) keywindow)->refCon;
  954.                 TEActivate(twp->texthand);
  955.                 scraptote();
  956.                 twp->textscrapped = FALSE;
  957.  
  958.                 ShowControl(twp->vBarHand);
  959.                 drawgrowicon(keywindow);
  960.             }
  961. #endif
  962. #ifdef USEHELPWINDOW                    
  963.             else if (((WindowPeek) keywindow)->windowKind == HELPWINDKIND) {
  964.                 /* forge an activate event */
  965.                 myEvent.message = keywindow;
  966.                 myEvent.what = activateEvt;
  967.                 myEvent.modifiers |= activeFlag);
  968.                 helpwhandle();
  969.             }
  970. #endif
  971.         }
  972.         shownnr();                            /* if "net not receiving" is up, show it */
  973.         return(TRUE);        
  974.     }
  975.     else {
  976.         /* MF is putting us in the background */            
  977.         setscript(0L);
  978.         hidennr();                            /* hide nnr */
  979.  
  980.         emwdeactivate();
  981.         mfbackground = TRUE;
  982.         GetPort(&oldport);
  983.         while (conp < conend) {
  984.             twp = *conp++;
  985.             if (twp == NULL || twp->emwindow == NULL)
  986.                 continue;
  987.                 
  988.             if (twp->icon_up) {
  989.                 /* redraw it for mf friendliness' sake */
  990.                 
  991.                 SetPort(twp->iconwindow);
  992.                 InvalRect(&((GrafPtr) twp->iconwindow)->portRect);
  993.             }
  994.             else if (twp->autoshrink) {
  995.                 /* shrink the em window automatically */
  996.                 shrinkwindow(twp);
  997.             }
  998.         }
  999. #ifdef USETEXTWINDOWS                    
  1000.         if (((WindowPeek) keywindow)->windowKind == TEXTWINDKIND) {
  1001.             twp = ((WindowPeek) keywindow)->refCon;
  1002.             TEDeactivate(twp->texthand);
  1003.             HideControl(twp->vBarHand);
  1004.             if (twp->textscrapped) {
  1005.                 tetoscrap(*TEScrHandle, TEScrLen);
  1006.             }
  1007.             drawgrowicon(keywindow);
  1008.         }
  1009. #endif
  1010. #ifdef USEHELPWINDOW                    
  1011.         if (((WindowPeek) keywindow)->windowKind == HELPWINDKIND) {
  1012.             /* forge an activate event */
  1013.             myEvent.message = keywindow;
  1014.             myEvent.what = activateEvt;
  1015.             myEvent.modifiers = 0;        /* !activeFlag */
  1016.             helpwhandle();
  1017.         }
  1018. #endif
  1019.         SetPort(oldport);
  1020.         return(FALSE);
  1021.     }
  1022. }
  1023.  
  1024.  
  1025. /* handle disk insertion event */
  1026.  
  1027. diskevent(anevent)
  1028. EventRecord * anevent;
  1029. {
  1030.     if (myEvent.message & 0xFFFF0000) {
  1031.         /* top word is error code for mount: an error occurred so 
  1032.             we should try to eject the disk, given that disk
  1033.             mounting is a long-winded synchronous process */
  1034.         Point where;
  1035.  
  1036.         where.h = 60;
  1037.         where.v = 60;
  1038.         DIBadMount(pass(where), myEvent.message);
  1039.     }
  1040. }
  1041.  
  1042.  
  1043. /* before we enter a modaldialog loop we need to check to make sure we're
  1044.     not in the background. */
  1045.     
  1046.     
  1047. chkbackground()
  1048. {
  1049.     EventRecord anevent;
  1050.  
  1051.     if (mfbackonly) {
  1052.         return(TRUE);
  1053.     }
  1054.     else if (mfbackground) {
  1055.         /* wait until we're brought into the foreground */
  1056.         while (TRUE) {
  1057.             SystemTask();                /* keep this if/until we use WaitNextEvent */
  1058.             if (GetNextEvent(app4Mask, &anevent)) {
  1059.                 /* wait for a mf switch in */
  1060.                 if (mfswitch(&anevent))
  1061.                     /* we've been switched in and can continue */
  1062.                     break;
  1063.             }
  1064.             else {
  1065.                 bkrd_service();
  1066.                 continue;        /* KS */
  1067.             }
  1068.         }
  1069.     }
  1070.     return(FALSE);
  1071. }
  1072.  
  1073.  
  1074. /* all event loops in the application call defaultevent() when the receive
  1075.     an event for which they have no handler */
  1076.     
  1077. defaultevent(anevent)
  1078. EventRecord * anevent;
  1079. {
  1080.     switch (anevent->what) {
  1081.         case diskEvt: {
  1082.             diskevent(anevent);
  1083.             break;
  1084.         }
  1085.         case app4Evt:  {
  1086.             mfswitch(anevent);
  1087.             break;
  1088.         }
  1089.     }
  1090. }
  1091.  
  1092. /* a bottleneck call... */
  1093.  
  1094. selectwindow(thewind)
  1095. WindowPtr thewind;
  1096. {
  1097.     if (thewind == FrontWindow())
  1098.         /* this is already the front window */
  1099.         return();
  1100.         
  1101.     emwdeactivate();        
  1102.         /* gotta do this first since apple WM delivers activate event FIRST??!! */
  1103.     SelectWindow(thewind);
  1104. }
  1105.  
  1106. /*    turn off the top window and turn on flags to indicate we're in the
  1107.     background now.
  1108.     
  1109.     NB there may be problems here with cursor turds if update 
  1110.     event following activate received following deactivate
  1111. */
  1112.  
  1113.  
  1114. emwdeactivate()
  1115. {
  1116.     GrafPtr oldport;
  1117.         
  1118.     ++bkrd_act;
  1119.     SetCursor(&arrow);
  1120.  
  1121.     if (keywindow == NULL || emwindow == NULL)
  1122.         return;
  1123.         
  1124.     GetPort(&oldport);
  1125.         
  1126.     if (keydp->emwindow == FrontWindow()) {
  1127.         SetPort(keydp->emwindow);
  1128.         if (keydp->curson) {
  1129.             InvertRect(&keydp->cursrect);
  1130.             keydp->curson = FALSE;
  1131.         }            /* must the cursor be deactivated ? */
  1132.         
  1133.         if (trackon) {
  1134.             InvertRect(&mouserect);
  1135.             trackon = FALSE;
  1136.         }
  1137.     }
  1138. #ifdef USETEXTWINDOWS
  1139.     if (keydp->textwindow == FrontWindow()) {
  1140.         SetPort(keydp->textwindow);
  1141.         TEDeactivate(keydp->texthand);
  1142.         HideControl(keydp->vBarHand);
  1143.         if (keydp->textscrapped) {
  1144.             tetoscrap(*TEScrHandle, TEScrLen);
  1145.             keydp->textscrapped = FALSE;
  1146.         }
  1147.         drawgrowicon(keydp->textwindow);
  1148.     }
  1149. #endif
  1150.     SetPort(oldport);
  1151. }
  1152.  
  1153.  
  1154. /* The following routines deal with converting the screen image to ASCII
  1155.     text without trailing spaces & CRs appended and saving/printing
  1156.     the resulting text */
  1157.  
  1158. /* same as ZeroScrap */
  1159.  
  1160. scrapzero()
  1161. {
  1162.     SetHandleSize(ScrapHandle, 0L);            /* set handle size to zero */
  1163.     *ScrapSize = 0;                                /* set length = type + len + text */
  1164. }
  1165.  
  1166.  
  1167. /* add text to the scrap:
  1168.     
  1169.     scrap format:    long type
  1170.                     text data:
  1171.                             long length
  1172.                             char []
  1173. */
  1174.  
  1175.  
  1176. puttextscrap(textp, length)
  1177. char * textp;
  1178. long length;
  1179. {
  1180.     Handle scraptemp;
  1181.     long oldlength;
  1182.     long offset;
  1183.     int result;
  1184.     
  1185.     LoadScrap();                                /* guarantee scrap in memory */
  1186.  
  1187.     scraptemp = NewHandle(0L);
  1188.         
  1189.     oldlength = GetScrap(scraptemp, 'TEXT', &offset);
  1190.     if (oldlength < 0 
  1191.         && oldlength != noTypeErr
  1192.         && oldlength != noScrapErr
  1193.     ) {
  1194.         /* a system error occurred */
  1195.         DisposHandle(scraptemp);
  1196.         return(-1);
  1197.     }
  1198.     else if (oldlength > 0) {
  1199.         /* text is present in scrap, we want to append */
  1200.         ZeroScrap();    /* IM 1-459 multiple appends don't work so kill old scrap */
  1201.         
  1202.         if (PtrAndHand(textp, scraptemp, length)) {
  1203.             DisposHandle(scraptemp);
  1204.             return(-1);
  1205.         }
  1206.         length += oldlength;
  1207.         
  1208.         MoveHHi(scraptemp);
  1209.         HLock(scraptemp);
  1210.         result = PutScrap(length, 'TEXT', *scraptemp);
  1211.         HUnlock(scraptemp);
  1212.     }
  1213.     else {
  1214.         /* no TEXT in scrap */
  1215.         result = PutScrap(length, 'TEXT', textp);
  1216.     }
  1217.     DisposHandle(scraptemp);
  1218.     if (result)
  1219.         return(-1);
  1220.     else
  1221.         return(0);
  1222. }
  1223.  
  1224.  
  1225. long gettextscrap(pthep)
  1226. long ** pthep;
  1227. {
  1228.     long length;
  1229.     long offset;
  1230.  
  1231.     LoadScrap();                                    /* guarantee scrap in memory */
  1232.  
  1233.     if (scraptemp == (Handle) NULL) {
  1234.         scraptemp = NewHandle(0L);
  1235.     }
  1236.     else {
  1237.         releasescrap();
  1238.         scraptemp = NewHandle(0L);
  1239.     }
  1240.         
  1241.     length = GetScrap(scraptemp, 'TEXT', &offset);
  1242.     if (length <= 0)
  1243.         return(0);
  1244.         
  1245.     HLock(scraptemp);
  1246.     *pthep = (long *)(* scraptemp);                        /* set data ptr */
  1247.     return(length);                                        /* return the length */
  1248. }
  1249.  
  1250. releasescrap()
  1251. {
  1252.     if (scraptemp != NULL) {
  1253.         HUnlock(scraptemp);
  1254.         DisposHandle(scraptemp);
  1255.         scraptemp = NULL;
  1256.     }
  1257. }
  1258.  
  1259.  
  1260. /* copies the selection or full screen if no selection;
  1261.     returns length, 0 on error */
  1262.  
  1263. getselection(copyp)
  1264. char * * copyp;
  1265. {
  1266.     int length;
  1267.     char * mapp;
  1268.     
  1269.     if (!memtest((long) (emdp->screensize + emdp->linelength + 2), ©err[0])) {
  1270.         /* not enough memory for operation */
  1271.         *copyp = NULL;
  1272.         return(0);
  1273.     }
  1274.     /* TODO should be from window struct */
  1275.     if (emdp->ibm_mode)
  1276.         mapp = scr_map;
  1277.     else
  1278.         mapp = &emdp->charr[0];
  1279.         
  1280.     *copyp = NewPtr((long) (emdp->screensize + emdp->linelength + 2));
  1281.     if (emdp->selrectset) {
  1282.         /* copy the user's selection rectangle */
  1283.         int selstart;
  1284.         int sellen;
  1285.         
  1286.         selstart = emdp->selystart * emdp->linelength + emdp->selxstart;
  1287.         sellen = emdp->selyend * emdp->linelength + emdp->selxend - selstart;
  1288.         if (sellen < 0) {
  1289.             /* something very wrong here! */
  1290.             DisposPtr(*copyp);
  1291.             *copyp = NULL;
  1292.             return(0);
  1293.         }
  1294.         else if (sellen == 0) {
  1295.             /* a null selection exists */
  1296.             selstart = 0;
  1297.             sellen = emdp->screensize;
  1298.         }
  1299.         length = screencopy(mapp, selstart, *copyp, sellen, FALSE);
  1300.     }
  1301.     else {
  1302.         /* copy the whole screen if no selection */
  1303.         length = screencopy(mapp, 0, *copyp, emdp->screensize, FALSE);
  1304.     }
  1305.     if (length == 0) {
  1306.         DisposPtr(*copyp);
  1307.         *copyp = NULL;
  1308.     }
  1309.     return(length);
  1310. }
  1311.  
  1312.  
  1313. /* if logging is on, append a line to the appropriate outputs, 
  1314.     skipping spaces and adding a CR */
  1315.  
  1316. /* todo MULTIWIND puttextscrap becomes textwappend */
  1317.  
  1318. saveline(copyp, len)
  1319. unsigned char * copyp;
  1320. int len;
  1321. {
  1322.     Ptr blankp;
  1323.     char acr;
  1324.     
  1325. #ifndef USETEXTWINDOWS
  1326.     if (mfpresent)
  1327.         /* make sure mf updates all client's scrap info */
  1328.         SystemEdit(EDCOPY - 1);
  1329.  
  1330.     if (!scrapzeroed) {
  1331.         /* zero the scrap the first time through */
  1332.         scrapzeroed = TRUE;
  1333.         ZeroScrap();
  1334.     }
  1335. #endif
  1336.     if (!emdp->logsession  && !emdp->filesession)
  1337.         return;
  1338.  
  1339. #ifdef IBMMODENOSCROLL    
  1340.     /* if this is enabled no session connect info scrolling off the top
  1341.         will be saved, which is    probably not what we want... */
  1342.     if (emdp->ibm_keymode)
  1343.         /* logging in ibm_keymode is done when PF key pressed */
  1344.         return;
  1345. #endif
  1346.  
  1347.     blankp = copyp + len;
  1348.     while (--blankp >= copyp) {
  1349.         /* skip blanks */
  1350.         if (*blankp != ' ')
  1351.             break;
  1352.     }
  1353.     if (blankp >= copyp) {
  1354.         /* we have non-blanks to copy */
  1355.         len = blankp - copyp + 1;
  1356.         if (emdp->logsession) {
  1357.             textwappend(copyp, (long) len);
  1358.         }
  1359.         if (emdp->filesession) {
  1360.             logappend(copyp, (long) len);
  1361.         }
  1362.     }
  1363.     /* add a carriage return */
  1364.     acr = CR;
  1365.     len = 1;
  1366.     if (emdp->logsession) {
  1367.         textwappend(&acr, (long) len);
  1368.     }
  1369.     if (emdp->filesession) {
  1370.         logappend(&acr, (long) len);
  1371.     }
  1372. }
  1373.  
  1374.  
  1375. /* if logging is on, append the screen to the textwindow and/or file */
  1376.  
  1377. savescreen()
  1378. {
  1379.     Ptr copyp;
  1380.     long len;
  1381.     
  1382. #ifndef USETEXTWINDOWS
  1383.     if (mfpresent)
  1384.         /* make sure mf updates all client's scrap info */
  1385.         SystemEdit(EDCOPY - 1);
  1386.  
  1387.     if (!scrapzeroed) {
  1388.         /* zero the scrap the first time through */
  1389.         scrapzeroed = TRUE;
  1390.         ZeroScrap();
  1391.     }
  1392. #endif
  1393.     if (emdp->logsession || emdp->filesession) {
  1394.         if ((len = getscreen(©p)) == 0) {
  1395.             DisposPtr(copyp);
  1396.             return;
  1397.         }
  1398.         if (emdp->logsession) {
  1399.             if (memtest(len, ©err[0])) {
  1400.                 /* not enough memory for operation */
  1401.                 textwappend(copyp, len);
  1402.             }
  1403.         }
  1404.         if (emdp->filesession)
  1405.             /* append screen to log file */
  1406.             logappend(copyp, len);
  1407.  
  1408.         DisposPtr(copyp);
  1409.     }
  1410. }
  1411.     
  1412.  
  1413.  
  1414. /* copies the full screen; returns length, 0 on error */
  1415.  
  1416. getscreen(copyp)
  1417. char * * copyp;
  1418. {
  1419.     int length;
  1420.     char * mapp;
  1421.     
  1422.     if (!memtest((long) (emdp->screensize + emdp->linelength + 2), ©err[0])) {
  1423.         /* not enough memory for operation */
  1424.         return(0);
  1425.     }
  1426.     /* TODO should be from window struct */
  1427.     if (emdp->ibm_mode)
  1428.         mapp = scr_map;
  1429.     else
  1430.         mapp = &emdp->charr[0];
  1431.         
  1432.     *copyp = NewPtr((long) (emdp->screensize + emdp->linelength + 2));
  1433.  
  1434.     /* copy the whole screen */
  1435.     length = screencopy(mapp, 0, *copyp, emdp->screensize);
  1436.     return(length);
  1437. }
  1438.  
  1439.  
  1440. /* saves/appends text */
  1441.  
  1442. savetext(action)
  1443. unsigned char action;
  1444. {
  1445.     char * copyp;            /* ptr to screen copy area */
  1446.     long len;            /* len of the screen copy */
  1447.     long fpos;            /* file pointer */
  1448.     /* Standard File dialog handles */
  1449.     Handle hsfreplace;                /* -3996 DITL */
  1450.     Ptr sfreplace;
  1451.     Handle hsfappend;                /* 128 DITL with "Append" rather than "Replace" */
  1452.     
  1453.  
  1454.     if (emdp->reply.fName[0] == 0) {
  1455.         /* if no file name has been specified, do a save as... */
  1456.         if (action == RF_SAVE)
  1457.             action = RF_SAVEAS;
  1458.         if (action == RF_APPEND)
  1459.             action = RF_APPENDTO;
  1460.     }
  1461.     /* set the text pointer/length */
  1462.     if (emdp->edit) {
  1463.         /* edit window is up */
  1464.         HLock((*emdp->texthand)->hText);
  1465.         copyp = *(*emdp->texthand)->hText;
  1466.         
  1467.         if ((*emdp->texthand)->selStart != (*emdp->texthand)->selEnd) {
  1468.             /* save the selection rather than the whole thing */
  1469.             copyp += (*emdp->texthand)->selStart;
  1470.             len = ((*emdp->texthand)->selEnd - (*emdp->texthand)->selStart);
  1471.         }
  1472.         else
  1473.             len = (*emdp->texthand)->teLength;
  1474.     }
  1475.     else {
  1476.         if ((len = getselection(©p)) == 0) {
  1477.             return;
  1478.         }
  1479.     }    
  1480.     if (action == RF_SAVE || action == RF_APPEND) {
  1481.         /* save or append to current file */
  1482.         if (FSOpen(&emdp->reply.fName, emdp->reply.vRefNum, &emdp->savefid)) {
  1483.             error(fileopenerr);
  1484.             return;
  1485.         }
  1486.         SetFPos(emdp->savefid, action == RF_APPEND ? fsFromLEOF : fsFromStart, (long) 0);
  1487.         /* position file ptr at EOF if append mode */
  1488.  
  1489.         if (FSWrite(emdp->savefid, &len, copyp))
  1490.             error(filewriteerr);
  1491.  
  1492.         GetFPos(emdp->savefid, &fpos);
  1493.         SetEOF(emdp->savefid, fpos);
  1494.         FSClose(emdp->savefid);
  1495.         FlushVol((StringPtr) NULL, 0);
  1496.         emdp->savefid = 0;
  1497.     }
  1498.     else if (action == RF_SAVEAS || action == RF_APPENDTO) {
  1499.     /* save as... or append to... do a dialog to get the filename/folder */
  1500.         Point here;
  1501.         char tbuf[256];
  1502.         char namebuf[256];
  1503.         
  1504.         here.v = 60;
  1505.         here.h = 100;
  1506.         centerpoint(&here);
  1507.         
  1508.         if (action == RF_APPENDTO) {
  1509.             sprintf(tbuf, "Append %s to:", emdp->seltype);
  1510.  
  1511.             /* switch Standard File dialog handles */
  1512.             hsfreplace = GetResource('DITL', -3996);                /* -3996 DITL */
  1513.             if (hsfreplace) {
  1514.                 HLock(hsfreplace);
  1515.                 HNoPurge(hsfreplace);
  1516.                 sfreplace = *hsfreplace;
  1517.             
  1518.                 hsfappend = GetResource('DITL', 128);                /* 128 DITL with "Append" rather than "Replace" */
  1519.                 HLock(hsfappend);
  1520.                 HNoPurge(hsfappend);
  1521.                 if (hsfappend)
  1522.                     *hsfreplace = *hsfappend;                    /* point to the other DITL */
  1523.             }
  1524.         }
  1525.         else {
  1526.             sprintf(tbuf, "Save %s as:", emdp->seltype);
  1527.         }
  1528.         ctop(tbuf);
  1529.         
  1530. #ifdef USELOGNAME
  1531.         /* automatic logging is assisted by a default name of "sessionname.log" */
  1532.         GetWTitle(emdp->emwindow, &namebuf[0]);
  1533.         ptoc(&namebuf[0]);
  1534.         strcat(&namebuf[0], ".log");
  1535.         ctop(&namebuf[0]);
  1536.         
  1537.         SFPutFile(pass(here), tbuf, &namebuf[0], (ProcPtr) NULL, &emdp->reply);
  1538. #else
  1539.         SFPutFile(pass(here), tbuf, &untitled[0], (ProcPtr) NULL, &emdp->reply);
  1540. #endif
  1541.  
  1542.         if (action == RF_APPENDTO) {
  1543.             /* switch back Standard File dialog handles */
  1544.             
  1545.             if (hsfreplace) {
  1546.                 *hsfreplace = sfreplace;
  1547.                 HUnlock(hsfreplace);
  1548.                 HPurge(hsfreplace);
  1549.                 ReleaseResource(hsfreplace);
  1550.                 if (hsfappend) {
  1551.                     HUnlock(hsfreplace);
  1552.                     HPurge(hsfreplace);
  1553.                     ReleaseResource(hsfappend);
  1554.                 }
  1555.             }
  1556.         }
  1557.         if (emdp->reply.good) {
  1558.             if (FSOpen(&emdp->reply.fName, emdp->reply.vRefNum, &emdp->savefid)) {
  1559.                 /* create new file if necessary */
  1560.                 if (Create(&emdp->reply.fName, emdp->reply.vRefNum, '????', 'TEXT')) {
  1561.                     error(filecreateerr);
  1562.                     return;
  1563.                 }
  1564.                 if (FSOpen(&emdp->reply.fName, emdp->reply.vRefNum, &emdp->savefid)) {
  1565.                     error(fileopenerr);
  1566.                     return;
  1567.                 }
  1568.             }
  1569.             filetitles(emdp);
  1570.             EnableItem(menu[FILEMENU], SAVESCREEN);
  1571.             EnableItem(menu[FILEMENU], APPENDSCREEN);
  1572.             
  1573.             if (action == RF_APPENDTO)
  1574.                 /* position file ptr at EOF */
  1575.                 SetFPos(emdp->savefid, fsFromLEOF, (long) 0);
  1576.             else 
  1577.                 SetFPos(emdp->savefid, fsFromStart, (long) 0);
  1578.             if (FSWrite(emdp->savefid, &len, copyp))
  1579.                 error(filewriteerr);
  1580.             GetFPos(emdp->savefid, &fpos);
  1581.             SetEOF(emdp->savefid, fpos);
  1582.  
  1583.     
  1584.             FSClose(emdp->savefid);
  1585.             FlushVol((StringPtr) NULL, 0);
  1586.             emdp->savefid = 0;
  1587.         }
  1588.         else {
  1589.             /* make sure the Pascal-string reply name is NULL, not "Untitled" */
  1590.             emdp->reply.fName[0] = 0;
  1591.         }
  1592.     }
  1593.     /* free the text pointer */
  1594.     if (emdp->edit)
  1595.         HUnlock((*emdp->texthand)->hText);
  1596.     else
  1597.         DisposPtr(copyp);
  1598. }
  1599.  
  1600.  
  1601. /* open a log file */
  1602.  
  1603. logopen()
  1604. {
  1605.     Point here;
  1606.     char namebuf[256];
  1607.     /* Standard File dialog handles */
  1608.     Handle hsfreplace;                /* -3996 DITL */
  1609.     Ptr sfreplace;
  1610.     Handle hsfappend;                /* 128 DITL with "Append" rather than "Replace" */
  1611.  
  1612.     /* set the text pointer/length */
  1613.     /* save as... or append to... do a dialog to get the filename/folder */
  1614.     here.v = 60;
  1615.     here.h = 100;
  1616.     centerpoint(&here);
  1617.     
  1618.     if (emdp->logreply.fName[0] == 0) {
  1619.         /* automatic logging is assisted by a default name of "sessionname.log" */
  1620.         GetWTitle(emdp->emwindow, &emdp->logreply.fName[0]);
  1621.         ptoc(&emdp->logreply.fName[0]);
  1622.         strcat(&emdp->logreply.fName[0], ".log");
  1623.         ctop(&emdp->logreply.fName[0]);
  1624.     }
  1625.     
  1626.     /* switch Standard File dialog handles */
  1627.     hsfreplace = GetResource('DITL', -3996);                /* -3996 DITL */
  1628.     if (hsfreplace) {
  1629.         HLock(hsfreplace);
  1630.         HNoPurge(hsfreplace);
  1631.         sfreplace = *hsfreplace;
  1632.     
  1633.         hsfappend = GetResource('DITL', 128);                /* 128 DITL with "Append" rather than "Replace" */
  1634.         HLock(hsfappend);
  1635.         HNoPurge(hsfappend);
  1636.         if (hsfappend)
  1637.             *hsfreplace = *hsfappend;                    /* point to the other DITL */
  1638.     }
  1639.     
  1640.     SFPutFile(pass(here), "\PLog session in file", &emdp->logreply.fName[0], (ProcPtr) NULL, &emdp->logreply);
  1641.  
  1642.     /* switch back Standard File dialog handles */
  1643.     if (hsfreplace) {
  1644.         *hsfreplace = sfreplace;
  1645.         HUnlock(hsfreplace);
  1646.         HPurge(hsfreplace);
  1647.         ReleaseResource(hsfreplace);
  1648.         if (hsfappend) {
  1649.             HUnlock(hsfreplace);
  1650.             HPurge(hsfreplace);
  1651.             ReleaseResource(hsfappend);
  1652.         }
  1653.     }
  1654.     if (emdp->logreply.good) {
  1655.         if (emdp->logfid) {
  1656.             /* if a log file has been opened, close it... */
  1657.             logclose();
  1658.         }
  1659.         if (FSOpen(&emdp->logreply.fName, emdp->logreply.vRefNum, &emdp->logfid)) {
  1660.             /* create new file if necessary */
  1661.             if (Create(&emdp->logreply.fName, emdp->logreply.vRefNum, '????', 'TEXT')) {
  1662.                 error(filecreateerr);
  1663.                 return;
  1664.             }
  1665.             if (FSOpen(&emdp->logreply.fName, emdp->logreply.vRefNum, &emdp->logfid)) {
  1666.                 error(fileopenerr);
  1667.                 return;
  1668.             }
  1669.         }
  1670.         filetitles(emdp);
  1671.         
  1672.         /* position file ptr at EOF */
  1673.         SetFPos(emdp->logfid, fsFromLEOF, (long) 0);
  1674.         return(TRUE);
  1675.     }
  1676.     return(FALSE);
  1677. }
  1678.  
  1679.  
  1680. /* close the log file */
  1681.  
  1682. logclose()
  1683. {
  1684.     if (emdp->logfid) {
  1685.         FSClose(emdp->logfid);
  1686.         FlushVol((StringPtr) NULL, 0);
  1687.         emdp->logfid = 0;
  1688.     }
  1689. }
  1690.  
  1691. /* log text in the selected log file */
  1692.  
  1693. logappend(copyp, len)
  1694. char * copyp;            /* ptr to screen copy area */
  1695. long len;            /* len of the screen copy */
  1696. {
  1697.     long fpos;            /* file pointer */
  1698.  
  1699.     if (emdp->logfid == 0) {
  1700.         if (!logopen()) {
  1701.             menufile(FILESESSION);        /* toggle logging off if user rejects */
  1702.             return;
  1703.         }
  1704.     }
  1705.     if (FSWrite(emdp->logfid, &len, copyp))
  1706.         error(filewriteerr);
  1707.  
  1708.     GetFPos(emdp->logfid, &fpos);
  1709.     SetEOF(emdp->logfid, fpos);
  1710. }
  1711.  
  1712.  
  1713. /* print a screen or the .edit window using the Streaming Text routines,
  1714.     which are no longer supported by Apple */
  1715.     
  1716. printtext(type)
  1717. {
  1718.     char * copyp;                        /* ptr to screen copy area */
  1719.     long len;                            /* len of the screen copy */
  1720.     unsigned char * thep;
  1721.     char * stakep;
  1722.     char * endp;
  1723.     int topmarg;                        /* 6 lines for top margin */
  1724.     char * leftmarg = "           ";     /* 11 spaces for 1.25" left marg */
  1725.     int linecount;
  1726.  
  1727.     if (emdp->edit) {
  1728.         /* edit window is up, print it */
  1729.         textwwrap(emdp);
  1730.         HLock((*emdp->texthand)->hText);
  1731.         copyp = *(*emdp->texthand)->hText;
  1732.         len = (*emdp->texthand)->teLength;
  1733.     }
  1734.     else {
  1735.         if ((len = getselection(©p)) == 0)
  1736.             goto PRINTABORT1;
  1737.     }
  1738.  
  1739.     thep = copyp;
  1740.     endp = copyp + len;
  1741.     
  1742.     /* use the Print Mgr streaming text routines */
  1743.     PrDrvrOpen();
  1744.     if (PrError()) {
  1745.         error("Can't open printer driver");
  1746.         goto PRINTABORT1;
  1747.     }
  1748.     PrCtlCall(iPrDevCtl, (long) lPrDocOpen, (long) 0, (long) 0);
  1749.     if (PrError()) {
  1750.         error("Can't open printer document");
  1751.         goto PRINTABORT2;
  1752.     }
  1753.     while (TRUE) {
  1754.         PrCtlCall(iPrDevCtl, (long) lPrPageOpen, (long) 0, (long) 0);
  1755.         if (PrError()) {
  1756.             error("Can't open printer page");
  1757.             goto PRINTABORT3;
  1758.         }
  1759.         for (topmarg = 6; --topmarg; ) {
  1760.             /* leave margin at top of page */
  1761.             PrCtlCall(iPrDevCtl, (long) lPrLFSixth, (long) 0, (long) 0);
  1762.         }
  1763.         stakep = thep;
  1764.         for (linecount = 0; thep < endp && linecount < 56; ) {
  1765.             /* print line by line */
  1766.             if (*thep++ == CR) {
  1767.                 /* print the line and do CRLF */
  1768.                 PrCtlCall(iPrIOCtl, leftmarg, (long) 11, (long) 0);
  1769.                 PrCtlCall(iPrIOCtl, stakep, (long) (thep - stakep), (long) 0);
  1770.                 PrCtlCall(iPrDevCtl, (long) lPrLFSixth, (long) 0, (long) 0);
  1771.                 stakep = thep;
  1772.                 linecount++;
  1773.             }
  1774.         }
  1775.         if (thep >= endp)
  1776.             break;
  1777.         PrCtlCall(iPrDevCtl, (long) lPrPageClose, (long) 0, (long) 0);
  1778.     }
  1779.     if (thep != stakep)
  1780.         /* print the last line */
  1781.         PrCtlCall(iPrIOCtl, stakep, (long) (thep - stakep), (long) 0);
  1782.     PrCtlCall(iPrDevCtl, (long) lPrPageClose, (long) 0, (long) 0);
  1783.  
  1784. PRINTABORT3:
  1785.     PrCtlCall(iPrDevCtl, (long) lPrDocClose, (long) 0, (long) 0);
  1786.  
  1787. PRINTABORT2:
  1788.     PrDrvrClose();
  1789.  
  1790. PRINTABORT1:
  1791.     if (emdp->edit) {
  1792.         textwunwrap(emdp);
  1793.         HUnlock((*emdp->texthand)->hText);
  1794.     }
  1795.     else {
  1796.         if (copyp != NULL)
  1797.             DisposPtr(copyp);
  1798.     }
  1799. }
  1800.  
  1801. short tabthreshold;        /* useless unless user can set it somehow... */
  1802.  
  1803. /*    copy screen from scr_map format into a buffer, returning count copied 
  1804.     target buffer must have (emdp->screensize + emdp->linelength) bytes minimum
  1805. */
  1806.  
  1807. screencopy(screenp, offset, destarr, count)
  1808. unsigned char * screenp;    /* points into scr_map to read from */
  1809. int offset;                    /* offset into map */
  1810. unsigned char * destarr;    /* points to dest to write into */
  1811. int count;                    /* scrp + count -> last char to copy, exclusive */
  1812. {
  1813.     register unsigned char * srcp = screenp + offset;
  1814.     register unsigned char * destp = destarr;
  1815.     register unsigned char * endp = srcp + count;    /* stake out the excluded end */
  1816.     register unsigned char * linep;                    /* temp */
  1817.     unsigned char * lineend;                        /* really beginning of next line */
  1818.     register unsigned char thechar;
  1819.     register int charcount;            /* # of good chars left in line */
  1820.     int firsttime = TRUE;                /* skip CR first time through loop */
  1821.     int spacesseen;                        /* copytable--spaces have been elided */
  1822.     int newrow;                            /* copytable--no tab for leading spaces */
  1823.     short invisible = FALSE;            /* default is no invisibles for ASCII */
  1824.     
  1825.     /* set up the charcount var for entry into the loop */
  1826.     lineend = screenp + (((offset / emdp->linelength)) * emdp->linelength);
  1827.         /* set up lineend, which will point to beginning of next line */
  1828.     charcount = 0;
  1829.     if (emdp->copytable) {
  1830.         /* adjust start */
  1831.         srcp -= emdp->selxstart;
  1832.     }
  1833.  
  1834.     if (emdp->ibm_mode) {
  1835.         /* hey, it's probably a good idea not to record invisible stuff! */
  1836.         invisible = (((ibm_attr(srcp)) & DSPD) == INVIS);
  1837.             /* if we're in an invisible field, note this fact */
  1838.     }    
  1839.     while (TRUE) {
  1840.         if (srcp >= endp)
  1841.             /* quit when we've done the work */
  1842.             break;
  1843.  
  1844.         if (--charcount <= 0) {
  1845.             /* it's either the end of the line or an initialization */
  1846.             if (!firsttime) {
  1847.                 /* put a CR after initialization */
  1848.                 *destp++ = CR;                            /* insert a CR for line end */
  1849.                 srcp = lineend;                            /* set srcp forward */
  1850.                 if (srcp >= endp)
  1851.                     /* quit when we've done the work */
  1852.                     break;
  1853.             }
  1854.             
  1855.             spacesseen = 0;
  1856.             newrow = TRUE;
  1857.             if (emdp->copytable 
  1858.                 && (emdp->selxend == 0 || emdp->selxstart < emdp->selxend)) {
  1859.                 
  1860.                 /* only copy within two x positions of selection start and end */
  1861.                 /* if range is negative, we do a regular copy */
  1862.                 
  1863.                 srcp += emdp->selxstart;
  1864.                 if (srcp >= endp)
  1865.                     /* quit when we've done the work */
  1866.                     break;
  1867.  
  1868.                 lineend += emdp->linelength;
  1869.                 if (emdp->selxend == 0) {
  1870.                     /* selxend is NOT included in the range, so it's 0 when the
  1871.                         end of line is selected! */
  1872.                     charcount = emdp->linelength - emdp->selxstart;
  1873.                     linep = lineend;
  1874.                 }
  1875.                 else {
  1876.                     charcount = emdp->selxend - emdp->selxstart;    
  1877.                     linep = lineend - emdp->linelength + emdp->selxend;
  1878.                 }
  1879.             }
  1880.             else {
  1881.                 lineend += emdp->linelength;
  1882.                 linep = lineend;
  1883.                 if (firsttime)
  1884.                     charcount = emdp->linelength - emdp->selxstart;
  1885.                 else
  1886.                     charcount = emdp->linelength;
  1887.             }
  1888.             for (--linep; charcount; --linep) {
  1889.                 /* go back up to beginning of line to elide empty space */
  1890.                 thechar = *linep;
  1891.                 if (        thechar == SPACE
  1892.                         ||    thechar == IBMNULL 
  1893.                         ||    thechar < ATTR) {
  1894.                         
  1895.                     charcount--;
  1896.                     continue;
  1897.                 }
  1898.                 else
  1899.                     break;
  1900.             }
  1901.                 
  1902.             if (firsttime) {
  1903.                 /* clear initialization flag */
  1904.                 firsttime = FALSE;
  1905.             }
  1906.             if (charcount <= 0) {
  1907.                 /* nothing on the whole line, skip it */
  1908.                 continue;
  1909.             }
  1910.             if (emdp->ibm_mode) {
  1911.                 /* check to find out what the current attribute is */
  1912.                 invisible = (((ibm_attr(srcp)) & DSPD) == INVIS);
  1913.                     /* if we're in an invisible field, note this fact */
  1914.             }    
  1915.         }
  1916.         /* copy the char from srcp to destp depending on the mode... */
  1917.         thechar = *srcp++;
  1918.         if (emdp->copytable) {
  1919.             if (    thechar == SPACE
  1920.                 || thechar == IBMNULL
  1921.                 )
  1922.             {
  1923.                 spacesseen++;
  1924.                 continue;
  1925.             }
  1926.             if (emdp->ibm_mode) {
  1927.                 if (thechar < ATTR) {
  1928.                     /* for ibm emulators hide invisible */
  1929.                     invisible = ((thechar & DSPD) == INVIS);
  1930.                     spacesseen++;
  1931.                     continue;
  1932.                 }
  1933.                 else if (invisible) {
  1934.                     spacesseen++;
  1935.                     continue;
  1936.                 }
  1937.             }
  1938.             if (spacesseen) {
  1939.                 /* TODO copy table threshold? */
  1940. #ifdef DONEWROW
  1941.                 /* automatically suppresses leading space -> TAB, not really
  1942.                     a good idea */
  1943.                 if (newrow)
  1944.                     newrow = FALSE;
  1945.                 else
  1946. #else
  1947.                 if (spacesseen < tabthreshold) {
  1948.                     /* if we've seen fewer spaces than the threshold,
  1949.                         put them out rather than a tab */
  1950.                     spacesseen++;        /* setup for predecrement */
  1951.                     while (--spacesseen) {
  1952.                         *destp++ = SPACE;
  1953.                     }
  1954.                     continue;
  1955.                 }
  1956. #endif
  1957.                 *destp++ = TAB;    /* stick in a TAB */
  1958.                 spacesseen = 0;
  1959.             }
  1960.             *destp++ = thechar;
  1961.             newrow = FALSE;            /* only skip leading blanks on new row */
  1962.         }
  1963.         else {
  1964.             /* ordinary, rather than copy table mode */
  1965.             if (emdp->ibm_mode) {
  1966.                 if (thechar < ATTR) {
  1967.                     *destp++ = SPACE;
  1968.                     invisible = ((thechar & DSPD) == INVIS);
  1969.                 }
  1970.                 else if ((thechar == IBMNULL) || invisible) {
  1971.                     /* use space for nulls and invisible chars */
  1972.                     *destp++ = SPACE;
  1973.                 }
  1974.                 else
  1975.                     *destp++ = thechar;
  1976.             }
  1977.             else
  1978.                 *destp++ = thechar;
  1979.         }
  1980.     }
  1981.     *destp = '\000';                /* put a null at the end for C-safety's sake */
  1982.     return(destp - destarr);        /* return length */
  1983. }
  1984.  
  1985. #ifdef MYSCRAP
  1986.  
  1987. tetoscrap(fromp, size)
  1988. char * fromp;
  1989. short size;
  1990. {
  1991.     if (memtest( (long) size, "to copy TextEdit Scrap to Clipboard")) {
  1992.         if ( ! ZeroScrap())
  1993.             if ( ! PutScrap((long) size, 'TEXT', fromp) )
  1994.                 if (! UnloadScrap())
  1995.                     return(size);
  1996.     }
  1997. }
  1998.  
  1999. scraptote()
  2000. {
  2001.     long size;
  2002.     long offset;
  2003.  
  2004.     if ( (size = GetScrap( (Handle) NULL, 'TEXT', &offset) ) > 0 ) {
  2005.         if (memtest((long) size * 2, "to copy Clipboard to TextEdit Scrap")) {
  2006.             /* * 2 for extra copy GetS makes */
  2007.             SetHandleSize(TEScrHandle, 0L);
  2008.             size = GetScrap(TEScrHandle, 'TEXT', &offset);
  2009.             if (size >= 0) {
  2010.                 TEScrLen = size;
  2011.                 return(size);
  2012.             }
  2013.         }
  2014.     }
  2015.     else if (size == noTypeErr)
  2016.         return(0L);
  2017. }
  2018.  
  2019. #else
  2020.  
  2021. tetoscrap(fromp, size)
  2022. char * fromp;
  2023. short size;
  2024. {
  2025.     if (memtest( (long) size, "to copy TextEdit Scrap to Clipboard")) {
  2026.         if ( ! ZeroScrap())
  2027.             if (! TEToScrap())
  2028.                 return(size);
  2029.     }
  2030.     return(0);
  2031. }
  2032.  
  2033.  
  2034. scraptote()
  2035. {
  2036.     long size;
  2037.     long offset;
  2038.  
  2039.     if ( (size = GetScrap( (Handle) NULL, 'TEXT', &offset) ) > 0 ) {
  2040.         if (memtest((long) size * 2, "to copy Clipboard to TextEdit Scrap")) {
  2041.             /* * 2 for extra copy GetS makes */
  2042.             if (!TEFromScrap()) {
  2043.                 return(size);
  2044.             }
  2045.         }
  2046.     }
  2047.     return(0);
  2048. }
  2049.  
  2050. #endif
  2051.  
  2052.  
  2053.  
  2054.  
  2055. /* clip DrawGrowIcon so the unused horizontal scrollbar zone isn't drawn */
  2056.  
  2057. drawgrowicon(updwind)
  2058. WindowPtr updwind;
  2059. {
  2060.     GrafPtr oport;
  2061.     RgnHandle oldclip;
  2062.     Rect iconrect;
  2063.     
  2064.     /* clip the drawing rgn so only the Grow Icon & vertical
  2065.         scrollbar are drawn */
  2066.     GetPort(&oport);
  2067.     SetPort(updwind);
  2068.     
  2069.     oldclip = NewRgn();
  2070.     GetClip(oldclip);
  2071.     
  2072.     iconrect.bottom = updwind->portRect.bottom;
  2073.     iconrect.right = updwind->portRect.right;
  2074.     iconrect.top = updwind->portRect.top;
  2075.     iconrect.left = iconrect.right - 15;
  2076.     
  2077.     ClipRect(&iconrect);
  2078.     DrawGrowIcon(updwind);
  2079.  
  2080.     SetClip(oldclip);
  2081.     DisposeRgn(oldclip);
  2082.  
  2083.     SetPort(oport);
  2084. }
  2085.  
  2086.  
  2087. #ifdef DOQDPRINT
  2088. /* print using QuickDraw */
  2089.  
  2090. #define INRANGE(thecount)    ((thecount >= (*hprec)->prJob.iFstPage)    \
  2091.                             &&     (thecount <= (*hprec)->prJob.iLstPage))
  2092.     /* this provides a range test to check whether we should draw... */
  2093.  
  2094. THPrint hprec;
  2095.  
  2096. QDprinttext(type, dodialog)
  2097. int type;
  2098. int dodialog;
  2099. {
  2100.     char * copyp;                        /* ptr to screen copy area */
  2101.     long len;                            /* len of the screen copy */
  2102.     unsigned char * thep;
  2103.     char * stakep;
  2104.     char * endp;
  2105.     int voffset;                        /* 6 lines for top margin */
  2106.     int hoffset;                        /* offset for text printing */
  2107.     int bottommarg;
  2108.     int pagecount;
  2109.     int linecount;
  2110.     int charcount;
  2111.     char pageno[255];    /* page number string for printing */
  2112.     int pageinrange;        /* flag to indicate page is in range */
  2113.     int copies;            /* number of copies */
  2114.     
  2115.     TPPrPort pport;
  2116.     TPrStatus pstat;
  2117.     GrafPtr oport;
  2118.     unsigned long omodflg;
  2119.     unsigned long oclrflg;
  2120.     int ofontsize;
  2121.     int olineheight;
  2122.     int ofont;
  2123.     int ohighfont;
  2124.     int ofontwidth;
  2125.     int ohoffset;
  2126.     int ovoffset;
  2127.     int ofontdescent;
  2128.     int ocolor;
  2129.     int device;
  2130.     
  2131.     GetPort(&oport);
  2132.     
  2133.     if (!memtest((long) 5000, "to print")) {
  2134.         /* WARNING:  2836 was observed, 5000 may not be worst case */
  2135.         return(0);
  2136.     }
  2137.  
  2138.     if (hprec == NULL) {
  2139.         hprec = NewHandle((long) sizeof(TPrint));
  2140.         PrintDefault(hprec);
  2141.         if (hprec == NULL)
  2142.             return(-1);
  2143.     }
  2144.     
  2145.     /* use the Print Mgr and QuickDraw to image the text */
  2146.     PrOpen();
  2147.     if (PrError()) {
  2148.         error("Can't open printer driver");
  2149.         goto PRQDABORT1;
  2150.     }
  2151.     if (dodialog) {
  2152.         emwdeactivate();
  2153.     
  2154.         if (!PrJobDialog(hprec))
  2155.             return(0);
  2156.     
  2157.     } 
  2158.     copies = (*hprec)->prJob.iCopies;
  2159.     device = (*hprec)->prStl.wDev >> 8;    /* high byte contains device type */
  2160.     
  2161.     if (type == RF_PRINTSCREEN) {
  2162.         if ((len = getselection(©p)) == 0)
  2163.             goto PRQDABORT2;
  2164.     }
  2165.     else if (type == RF_PRINTTEXT) {
  2166.         HLock((*emdp->texthand)->hText);
  2167.         copyp = *(*emdp->texthand)->hText;
  2168.         len = (*emdp->texthand)->teLength;
  2169.     }
  2170.     else if (type == RF_PRINTSCRAP) {
  2171.         /* print the clipboard */
  2172.         if (! (len = gettextscrap(©p)))
  2173.             goto PRQDABORT2;
  2174.     }
  2175.  
  2176.     pport = PrOpenDoc(hprec, (long) 0, (long) 0);
  2177.     if (PrError()) {
  2178.         error("Can't open printer document");
  2179.         goto PRQDABORT2;
  2180.     }
  2181.     
  2182.     omodflg = modflg;
  2183.     oclrflg = clrflg;
  2184.     ofontsize = emdp->fontsize;
  2185.     olineheight = emdp->lineheight;
  2186.  
  2187.     ofont = emdp->normfont;
  2188.     ohighfont = emdp->highfont;
  2189.     ofontwidth = fontwidth;
  2190.     ohoffset = emdp->hoffset;
  2191.     ovoffset = emdp->voffset;
  2192.     ofontdescent = emdp->fontdescent;
  2193.     ocolor = emdp->color;
  2194.     
  2195.     while (copies--) {
  2196.         /* and now we do the drawing */
  2197.         charcount = 0;
  2198.         pagecount = 0;
  2199.         thep = copyp;
  2200.         endp = copyp + len;
  2201.         
  2202.         if (type == RF_PRINTTEXT) {
  2203.             int  *lStart  = &(*emdp->texthand)->lineStarts[0];
  2204.  
  2205.             while (TRUE) {
  2206.                 /* go through a number of pages */
  2207.                 pagecount++;
  2208.                 
  2209.                 if ((pageinrange = INRANGE(pagecount))) {
  2210.                     PrOpenPage(pport, (long) 0);
  2211.                 }
  2212.                 if (PrError()) {
  2213.                     error("Can't open printer page");
  2214.                     goto PRQDABORT3;
  2215.                 }
  2216.                 
  2217.                 /* interpret size and font literally for .edit window,
  2218.                     unless we're using a Laser Writer */
  2219.                     
  2220.                 TextFont(emdp->normfont);
  2221.                 TextSize(emdp->fontsize);
  2222.                 hoffset = fontwidth * 12;
  2223.                 if (emdp->fontsize == 12)
  2224.                     hoffset = fontwidth * 8;
  2225.                 else if (emdp->fontsize == 16)
  2226.                     hoffset = 2;
  2227.                 
  2228.                 if (device == bDevLaser) {
  2229.                     /* LaserWriter will use 36 pt (actually 50 pt) font 
  2230.                         so we can enhance print quality */
  2231.                     if (courierprint) {
  2232.                         TextFont(monaco);
  2233.                         TextSize(9);
  2234.                         emdp->lineheight = 12;
  2235.                         hoffset = 50;
  2236.                     }
  2237.                     else {
  2238.                         TextSize(9);
  2239.                         emdp->lineheight = 12;
  2240.                         hoffset = 50;
  2241.                     }
  2242.                 }
  2243.                 voffset = 48;
  2244.                 bottommarg = (*hprec)->prInfo.rPage.bottom - (3 * emdp->lineheight);
  2245.                 
  2246.                 stakep = thep;
  2247.                 for (linecount = 0; thep < endp; thep++, charcount++) {
  2248.                     /* print line by line leaving ~ an inch margin at the bottom*/
  2249.                     if (charcount >= *lStart) {
  2250.                         /* we're at or past a line break, position cursor & draw line */
  2251.                         if (pageinrange) {
  2252.                             MoveTo(hoffset, voffset);
  2253.                             DrawText(stakep, 0, (thep - stakep));
  2254.                         }
  2255.                         stakep = thep;
  2256.                         linecount++;
  2257.                         lStart++;
  2258.  
  2259.                         voffset += emdp->lineheight;
  2260.                         if (voffset > bottommarg) {
  2261.                             /* at bottom of page */
  2262.                             if (pageinrange) {
  2263.                                 voffset += 2 * emdp->lineheight;
  2264.                                 sprintf(pageno, "%5d", pagecount);
  2265.                                 MoveTo( ((*hprec)->prInfo.rPage.right 
  2266.                                         - (*hprec)->prInfo.rPage.left) / 2 - 30,
  2267.                                     voffset);
  2268.                                 DrawText(pageno, 0, strlen(pageno));
  2269.                             }
  2270.                             break;
  2271.                         }
  2272.                     }
  2273.                 }
  2274.                 if (thep >= endp) {
  2275.                     /* we've gone through the whole text */
  2276.                     if (thep != stakep) {
  2277.                         /* print the last line */
  2278.                         if (pageinrange) {
  2279.                             MoveTo(hoffset, voffset);
  2280.                             DrawText(stakep, 0, (thep - stakep));
  2281.                         }
  2282.                     }
  2283.                     if (pageinrange) {
  2284.                         /* print last page # */
  2285.                         if (pageinrange) {
  2286.                             voffset = bottommarg;
  2287.                             voffset += 2 * emdp->lineheight;
  2288.                             sprintf(pageno, "%5d", pagecount);
  2289.                             MoveTo( ((*hprec)->prInfo.rPage.right 
  2290.                                     - (*hprec)->prInfo.rPage.left) / 2 - 30,
  2291.                                 voffset);
  2292.                             DrawText(pageno, 0, strlen(pageno));
  2293.                         }
  2294.                         PrClosePage(pport);
  2295.                     }
  2296.                     break;                /* print next copy */
  2297.                 }
  2298.                 if (pageinrange) {
  2299.                     PrClosePage(pport);
  2300.                 }
  2301.             }
  2302.         }
  2303.         else {
  2304.             /* print the image on the emulator screen */
  2305.             PrOpenPage(pport, (long) 0);
  2306.             if (PrError()) {
  2307.                 error("Can't open printer page");
  2308.                 goto PRQDABORT3;
  2309.             }
  2310.             
  2311.             /* emdp->color = TRUE;            color on to get inverse text */
  2312.             TextFont(emdp->normfont);
  2313.             TextSize(emdp->fontsize);
  2314.             emdp->hoffset = fontwidth * 12;
  2315.             if (emdp->fontsize == 12)
  2316.                 emdp->hoffset = fontwidth * 8;
  2317.             else if (emdp->fontsize == 16)
  2318.                 emdp->hoffset = 2;
  2319.             
  2320.             emdp->voffset = 72;        /* leave an inch at the top */
  2321.  
  2322. #ifdef DUPESERIAL
  2323.             /* we might as well let the user get the size they're using... */
  2324.             if (device == bDevCItoh) {
  2325.                 /* will use 16 point font on ImageWriter? */
  2326.                 TextSize(16);
  2327.                 emdp->fontsize = 16;
  2328.                 emdp->lineheight = 12;
  2329.                 fontwidth = 6;
  2330.                 emdp->fontdescent = 4;
  2331.             }
  2332.             else 
  2333. #endif            
  2334.             if (device == bDevLaser) {
  2335.                 /* LaserWriter will use 48 pt (actually 50 pt) font */
  2336.                 if (courierprint) {
  2337.                     emdp->normfont = monaco; /* force to use Courier rather than our font */
  2338.                     emdp->highfont = monaco;
  2339.                     
  2340.                     TextFont(emdp->normfont);
  2341.                 }
  2342.                 TextSize(9);
  2343.                 emdp->fontsize = 9;
  2344.                 emdp->lineheight = 12;
  2345.                 fontwidth = 6;
  2346.                 emdp->fontdescent = 3;
  2347.                 emdp->hoffset = 50;
  2348.             }
  2349.             bottommarg = (*hprec)->prInfo.rPage.bottom - (6 * emdp->lineheight);
  2350.  
  2351.             /* temporarily mark screen as all modified and all clear */
  2352.             modflg = SCRALLMOD;
  2353.             clrflg = SCRALLMOD;
  2354.             
  2355.             if (emdp->ibm_mode) {
  2356.                 ibmpaintbuf(scr_map, FALSE);
  2357.                 /* draw the screen but NOT the selection */
  2358.             }
  2359.             else {
  2360.                 paintbuf(&emdp->charr[0], FALSE);
  2361.                 /* draw the screen but NOT the selection */
  2362.             }
  2363.             PrClosePage(pport);
  2364.         }
  2365.     }
  2366.  
  2367. PRQDABORT3:
  2368.     PrCloseDoc(pport);
  2369.     
  2370.     if ((*hprec)->prJob.bJDocLoop == bSpoolLoop && !PrError()) {
  2371.         PrPicFile(hprec, NULL, NULL, NULL, &pstat);
  2372.     }
  2373.     
  2374.     modflg = omodflg;
  2375.     clrflg = oclrflg;
  2376.     fontwidth = ofontwidth;
  2377.     emdp->normfont = ofont;
  2378.     emdp->highfont = ohighfont;
  2379.     emdp->fontsize = ofontsize;
  2380.     emdp->lineheight = olineheight;
  2381.     emdp->hoffset = ohoffset;
  2382.     emdp->voffset = ovoffset;
  2383.     emdp->fontdescent = ofontdescent;
  2384.     emdp->color = ocolor;
  2385.     
  2386. PRQDABORT2:
  2387.     PrClose();
  2388.     
  2389. PRQDABORT1:
  2390.     if (type == RF_PRINTSCREEN) {
  2391.         if (copyp != NULL)
  2392.             DisposPtr(copyp);
  2393.     }
  2394.     else if (type == RF_PRINTTEXT) {
  2395.         HUnlock((*emdp->texthand)->hText);
  2396.     }
  2397.     else if (type == RF_PRINTSCRAP) {
  2398.         releasescrap();
  2399.     }
  2400.     /* DisposHandle(hprec);        
  2401.         hprec = NULL;
  2402.         leave it around once it's allocated */
  2403.  
  2404.     SetPort(oport);
  2405. }
  2406.  
  2407.  
  2408. #endif
  2409.  
  2410. /* rlincopy-- do a special copy routine for RLIN library format records
  2411.         which converts RLIN to NOTIS format
  2412.  
  2413. here follow the formats... 
  2414.  
  2415. A sample RLIN name authority record...  book description record is the other
  2416. important case...
  2417.  
  2418. ID: NAF = Name Authority File
  2419. _____________________________
  2420.         FIN HP BECKER ERNEST - Record 1.1.1
  2421.  
  2422.    ID:NAFL506215      ST:p    EL:n   STH:a    MS:n   UIP:a    TD:19840322000000
  2423.    KRC:a    NMU:a    CRC:c   UPN:a   SBU:a   SBC:a   DID:n    DF:04-08-80
  2424.    RFE:n    CSC:     SRU:b   SRT:n   SRN:n   TSS:    TGA:?   ROM:?   MOD:
  2425.    VST:d 06-08-84            
  2426.    040    DLC$cDLC
  2427.    100 10 Becker, Ernest.
  2428.    670    His Zen: a rational critique, 1961.
  2429.    678    1924-1974
  2430.  
  2431.     
  2432. All fields from ID: through MOD: are derived from a fixed field type 008
  2433.      
  2434. 008:  :NAFL506215pnana198403220000000aaca ....  some fields are ignored...
  2435.     contains 40 characters, fixed length
  2436.     0-5 date yymmdd
  2437.     6 DID:
  2438.     7 ROM:
  2439.     8 blank
  2440.     9 KRC
  2441.     10 CRC
  2442.     11 SBC (subject heading?)
  2443.     12 SRT
  2444.     13 SRN
  2445.     14 NMU
  2446.     15 SBU
  2447.     16 SRU
  2448.     17 TSS
  2449.     18-27 undefined (blank)
  2450.     28 TGA
  2451.     29 RFE
  2452.     30 blank
  2453.     31 always 'a'
  2454.     32 UPN
  2455.     33 EL?
  2456.     34-37 undefined (blank)
  2457.     38 MOD
  2458.     39 CSC
  2459.  
  2460. 040:  :DLC|cDLC
  2461. 100:10:Becker, Ernest.
  2462. 670:  :His Zen: a rational critique, 1961.
  2463. 678:  :1924-1974
  2464.  
  2465. NOTIS needs ^A (EOF) appended to the end of each field (line), CR not needed
  2466.             $ needs to be translated to |
  2467.    
  2468.  
  2469. Questions about the RLIN record:  
  2470.     what is the length of the ID: and other variable length fields?
  2471.     are the field titles invariant?  
  2472.     does the number of fields vary?
  2473.  
  2474. RLIN book record
  2475. _________________
  2476.       FIN PN BETH, R - Cluster 1 of 1
  2477.  
  2478.   ID:UKBPGB8947110-B  RTYP:c    ST:p   FRN:     MS:p      EL:       AD:04-04-90
  2479.   CC:9662  BLT:am      DCF:a   CSC:d   MOD:    SNR:      ATC:       UD:01-01-01
  2480.   CP:enk     L:eng     INT:    GPC:    BIO:    FIC:0     CON:
  2481.   PC:s      PD:1990/           REP:    CPI:0   FSI:0     ILC:a     MEI:1   II:0
  2482.   MMD:      OR:    POL:     DM:     RR:        COL:      EML:      GEN:   BSE:
  2483.     ---> irrelevant microfilm record...
  2484.  
  2485.   010     GB8947110
  2486.   015     GB89-47110
  2487.   020     070903931X :$cL11.95
  2488.   035     (Uk)070903931x
  2489.   040     Uk$cUk$dDLC$dCStRLIN
  2490.   050 14  BF1566
  2491.   082 04  133.43$220
  2492.   100 10  Beth, Rae.
  2493.   245 10  Hedge witch :$ba guide to solitary witchcraft /$cRae Beth.
  2494.   260 0   London :$bHale,$c1990.
  2495.   300     189 p. :$bill. ;$c23 cm.
  2496.   653     Witchcraft
  2497.   650  0  Witchcraft.
  2498.   886 2   $2UK MARC$a016$b00#a100=NOTNAL
  2499.   886 2   $2UK MARC$a690$b00#z21030#awitchcraft
  2500.   886 2   $2UK MARC$a691$b00#a0001260
  2501. :+?     ^throw away third character in sub-ID field:  added by RLIN but not used!
  2502.  
  2503. MARC number   NOTIS label   RLIN label    name of field
  2504.  
  2505. *008/00-05    DT        AD        date entered on file
  2506. 008/06        D/CODE         PC        type of date
  2507. 008/07-10     DT/1      PD        date 1
  2508. 008/11-14     DT/2      (in PD with slash between: 1988/1989)   date 2
  2509. 008/15-17     PLACE          CP        place of publ.
  2510. 008/18-21     ILLUS          ILC       illustrations
  2511. 008/22        T/AUD          INT       Target audience
  2512. 008/23        REPRO          REP       form of item
  2513. 008/24-27     CONT      CON       nature of contents
  2514. 008/28        GOVT      GPC       government publication
  2515. 008/29        CONF      CPI       conference publication
  2516. 008/30        FEST      FSI       Festschrift
  2517. 008/31        INDX      II        index
  2518. 008/32        ME/B      MEI       main entry in description
  2519. 008/33        FICT      FIC       fiction
  2520. 008/34        BIOG      BIO       biography
  2521. 008/35-37     LANG      L         language
  2522. 008/38        MOD       MOD       modified record
  2523. 008/39        SRC       CSC       cataloging source
  2524.  
  2525. *supplied by NOTIS when new record is created
  2526. Both the RLIN & NOTIS headers have additional information which is specific to
  2527. their systems.
  2528.  
  2529. */
  2530.  
  2531. rlincopy(type)
  2532. int type;
  2533. {
  2534.     long copylen;
  2535.     int count;
  2536.     int count2;
  2537.     int scancount;
  2538.     int slen;                    /* length of string */
  2539.     char * rlintext;            /* src text from RLIN */
  2540.     register char * rlinp;
  2541.     Ptr notistext;                /* destination text */
  2542.     register char * notisp;
  2543.     register char * tempp;
  2544.     long notislen;
  2545.     char rnum[255];
  2546.     char rsub[5];
  2547.     char rline[255];
  2548.     int firsttime = TRUE;
  2549.     int blankcount;
  2550.     
  2551. /* RLIN name authority tags */
  2552.     char DID;
  2553.     char ROM;
  2554.     char KRC;
  2555.     char CRC;
  2556.     char SBC;
  2557.     char SRT;
  2558.     char SRN;
  2559.     char NMU;
  2560.     char SBU;
  2561.     char SRU;
  2562.     char TSS;
  2563.     char TGA;
  2564.     char RFE;
  2565.     char UPN;
  2566.     char EL;
  2567.     char MOD;
  2568.     char CSC;
  2569.     char STH;
  2570.     char UIP;
  2571.     
  2572. /* RLIN book record tags */
  2573.     char PC;
  2574.     char PD1[50];        /* 4 byte date */
  2575.     char PD2[50];        /* 4 byte date */
  2576.     char CP[50];        /* 3 */
  2577.     char ILC[50];        /* 4 */
  2578.     char INT;
  2579.     char REPR;
  2580.     char CON[50];        /* 4 */
  2581.     char GPC;
  2582.     char CPI;
  2583.     char FSI;
  2584.     char II;
  2585.     char MEI;
  2586.     char FIC;
  2587.     char BIO;
  2588.     char LAN[50];        /* 3 */
  2589. /* shared with NAF... 
  2590.     char MOD;
  2591.     char CSC;
  2592. */
  2593.     if (type == 'C') {
  2594.         /* clear the scrap */
  2595.         ZeroScrap();
  2596.         return;
  2597.     }
  2598.     
  2599.     if ((copylen = getselection(&rlintext)) == 0) {
  2600.         return;
  2601.     }
  2602.     rlinp = rlintext;
  2603.     
  2604.     if (!memtest((long) copylen + 2000, ©err[0])) {
  2605.         /* not enough memory for operation */
  2606.         DisposPtr(rlintext);
  2607.         return;
  2608.     }
  2609.  
  2610.     notistext = NewPtr((Size) (copylen + 2000));
  2611.     if (notistext == NULL) {
  2612.         beep();
  2613.         return;
  2614.     }
  2615.     notisp = notistext;
  2616.     
  2617.     count = copylen;
  2618.     tempp = rlintext;
  2619.     while (count--) {
  2620.         /* all CRs to NULL to terminate lines as strings */
  2621.         if (*tempp == CR)
  2622.             *tempp = '\000';
  2623.         tempp++;
  2624.     }
  2625.     count = copylen;
  2626.  
  2627.     switch (type) {
  2628.         case 'a': {
  2629.             /* RLIN name authority file record */
  2630.             
  2631.             /* skip white space */
  2632.             for ( ; *rlinp == ' '; rlinp++, count--) 
  2633.                 ;
  2634.                 
  2635.             if (strncmp(rlinp, "ID:", 3) == 0) {
  2636.                     /* RLIN ID appears at the beginning of a record... 
  2637.                         we must assemble a 008 line from several tagged lines at the beginning */
  2638.                     
  2639.                 ZeroScrap();            /* clear the old scrap, this is a new record */
  2640.                 scancount = sscanf(rlinp, 
  2641.                     "%*s%*s EL:%c STH:%c %*s UIP:%c",
  2642.                     &EL, &STH, &UIP
  2643.                 );
  2644.                 if (scancount != 3) {
  2645.                     /* hey, wrong format! */
  2646.                     beep();
  2647.                     DisposPtr(notistext);
  2648.                     DisposPtr(rlinp);
  2649.                     return(-1);
  2650.                 }
  2651.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2652.                     
  2653.                 for ( ; *rlinp == ' '; rlinp++, count--) 
  2654.                     ;
  2655.                 scancount = sscanf(rlinp, 
  2656.                     "KRC:%c NMU:%c CRC:%c UPN:%c SBU:%c SBC:%c DID:%c",
  2657.                     &KRC,       &NMU,  &CRC,  &UPN,  &SBU,  &SBC,  &DID
  2658.                 );
  2659.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2660.     
  2661.                 MOD = ' ';        /* space may be skipped by copy at end of line */
  2662.                 for ( ; *rlinp == ' '; rlinp++, count--) 
  2663.                     ;
  2664.                 scancount = sscanf(rlinp, 
  2665.                     "RFE:%c CSC:%c SRU:%c SRT:%c SRN:%c TSS:%c TGA:%c ROM:%c MOD:%c",
  2666.                          &RFE,  &CSC,  &SRU,  &SRT,  &SRN,  &TSS,  &TGA,  &ROM,  &MOD
  2667.                 );
  2668.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2669.                 
  2670.                 sprintf(notisp, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", 
  2671.                     CTLB, PT, EL, CSC, ROM, MOD, UPN, TGA, SBC, DID, TSS, SRN, SRT, NMU,
  2672.                     SBU, SRU, KRC, STH, RFE, UIP, CRC);
  2673.                     /* CTLB overrides pastemode in 3270 ED_PASTE, PT is Tab, need to tab to first field to start */
  2674.                     
  2675.                 notisp += strlen(notisp);
  2676.  
  2677.                 /* skip next line */
  2678.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2679.             }
  2680.             break;
  2681.         }
  2682.         case 'b': {
  2683.             /* RLIN book record */
  2684.             
  2685.             /* skip white space */
  2686.             for ( ; *rlinp == ' '; rlinp++, count--) 
  2687.                 ;
  2688.                 
  2689.             if (strncmp(rlinp, "ID:", 3) == 0) {
  2690.                     /* RLIN ID appears at the beginning of a record... 
  2691.                         we must assemble a 008 line from several tagged lines at the beginning */
  2692.                     
  2693.                 ZeroScrap();            /* clear the old scrap, this is a new record */
  2694.                 
  2695.                 /* skip the first line */
  2696.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2697.     
  2698.                 for ( ; *rlinp == ' '; rlinp++, count--) 
  2699.                     ;
  2700.                 scancount = sscanf(rlinp, 
  2701.                     "%*s %*s %*s CSC:%c MOD:%c",
  2702.                                      &CSC,  &MOD
  2703.                 );
  2704.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2705.                 if (scancount != 2) {
  2706.                     /* hey, wrong format! */
  2707.                     beep();
  2708.                     DisposPtr(notistext);
  2709.                     DisposPtr(rlinp);
  2710.                     return(-1);
  2711.                 }
  2712.                 for ( ; *rlinp == ' '; rlinp++, count--) 
  2713.                     ;
  2714.                 CON[0] = ' ';
  2715.                 CON[1] = ' ';
  2716.                 CON[2] = ' ';
  2717.                 CON[3] = ' ';
  2718.                 scancount = sscanf(rlinp, 
  2719.                       "CP:%c%c%c L:%c%c%c INT:%c GPC:%c BIO:%c FIC:%c CON:%4s",
  2720.                          &CP[0], &CP[1], &CP[2], 
  2721.                                    &LAN[0], &LAN[1], &LAN[2],   
  2722.                                               &INT,  &GPC,  &BIO,  &FIC,  &CON
  2723.                 );
  2724.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2725.  
  2726.                 CP[3] = '\000';
  2727.                 LAN[3] = '\000';
  2728.                 /* CON may be truncated since it's at the end of the line */
  2729.                 if (CON[0] == '\000') CON[0] = ' ';
  2730.                 if (CON[1] == '\000') CON[1] = ' ';
  2731.                 if (CON[2] == '\000') CON[2] = ' ';
  2732.                 if (CON[3] == '\000') CON[3] = ' ';
  2733.                 CON[4] = '\000';
  2734.                 
  2735.                 PD1[4] = '\000';
  2736.                 PD2[4] = '\000';
  2737.                 ILC[4] = '\000';
  2738.                 for ( ; *rlinp == ' '; rlinp++, count--) 
  2739.                     ;
  2740.                 scancount = sscanf(rlinp, 
  2741.                       "PC:%c PD:%c%c%c%c%*c%c%c%c%c REP:%c CPI:%c FSI:%c ILC:%c%c%c%c MEI:%c II:%c",
  2742.                          &PC, &PD1[0], &PD1[1], &PD1[2], &PD1[3], 
  2743.                          &PD2[0], &PD2[1], &PD2[2], &PD2[3], 
  2744.                          &REPR,  &CPI,  &FSI, &ILC[0], &ILC[1], &ILC[2], &ILC[3],  &MEI, &II
  2745.                 );
  2746.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2747.  
  2748.                 /* we now have the first line of the NOTIS record, so we can put it out...*/
  2749.                 sprintf(notisp, "%c%c%c%c%c%c%c%c%3s%3s%c%c%c%c%4s%4s%4s%4s%c%c%c%c%c%c%c", 
  2750.                     CTLB, PT, PT, PT, PT, PT, PT, CSC, &CP, &LAN, MOD, INT, REPR, PC, 
  2751.                     &PD1, &PD2, &CON, &ILC, GPC, BIO, FSI, CPI, FIC, II, MEI); 
  2752.                     /* CTLB overrides pastemode in 3270 ED_PASTE, PT is Tab, need to tab to first field to start */
  2753.                     
  2754.                 notisp += strlen(notisp);
  2755.  
  2756.                 /* skip next line */
  2757.                 slen = strlen(rlinp) + 1; rlinp += slen; count -= slen; if (count < 0) break;
  2758.     
  2759.             }
  2760.             break;
  2761.         }
  2762.         default: {
  2763.             DisposPtr(notistext);
  2764.             DisposPtr(rlintext);
  2765.             return(-1);
  2766.         }
  2767.     }
  2768.     /* we continue to copy lines which have a similar format */
  2769.     while (count > 0) {
  2770.         /* now translate the remaining lines from RLIN to NOTIS format */
  2771.         blankcount = 0;
  2772.         for ( ; *rlinp == ' '; rlinp++, count--) 
  2773.             blankcount++;
  2774.             
  2775.         if (strncmp(rlinp, ":+", 2) == 0)
  2776.         /* RLIN prompt is obviously the end of a record... */
  2777.             break;
  2778.         
  2779.         /* convert $ to IBM field separator */
  2780.         tempp = rlinp;
  2781.         slen = strlen(rlinp);
  2782.         while (slen--) {
  2783.             if (*tempp == '$') 
  2784.                 *tempp = IBMK_RS;
  2785.             tempp++;
  2786.         }
  2787.  
  2788.         if (blankcount < 4) {
  2789.             /* new field rather than continuation */
  2790.             if (!firsttime) {
  2791.                 *notisp++ = IBMK_FS;                /* add End of Field marker at end of previous line */
  2792.             }
  2793.             firsttime = FALSE;
  2794.             
  2795.             scancount = sscanf(rlinp, "%254s%*c%c%c%*c%254[^\000]", 
  2796.                             &rnum, &rsub[0], &rsub[1], &rline);
  2797.             slen = strlen(rlinp) + 1; rlinp += slen; count -= slen;
  2798.             
  2799.             sprintf(notisp, "%254s:%c%c:%254s", &rnum, rsub[0], rsub[1], &rline);
  2800.             notisp += strlen(notisp);
  2801.         }
  2802.         else {
  2803.             scancount = sscanf(rlinp, "%254[^\000]", 
  2804.                             &rline);
  2805.             slen = strlen(rlinp) + 1; rlinp += slen; count -= slen;
  2806.             
  2807.             sprintf(notisp, " %254s", &rline);
  2808.             notisp += strlen(notisp);
  2809.         }
  2810.     }
  2811.     *notisp++ = IBMK_FS;                /* add End of Field marker at end of last line? */
  2812.     
  2813.     notislen = notisp - notistext;
  2814.  
  2815.     DisposPtr(rlintext);
  2816.  
  2817.     puttextscrap(notistext, notislen);
  2818.     
  2819.     DisposPtr(notistext);
  2820.  
  2821.     if (edresetselect)
  2822.         selreset(emdp);
  2823.         
  2824.     return(0);
  2825. }